scribe-cms 0.0.2 → 0.0.4
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 +2 -3
- package/bin/scribe.js +2 -11
- package/dist/cli/index.cjs +1284 -171
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +1284 -171
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-translate.d.ts +16 -0
- package/dist/cli/prompt-translate.d.ts.map +1 -0
- package/dist/cli/translate-progress.d.ts +11 -0
- package/dist/cli/translate-progress.d.ts.map +1 -0
- package/dist/index.cjs +479 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +475 -102
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +12 -2
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +12 -2
- package/dist/runtime.js.map +1 -1
- package/dist/src/core/field.d.ts +2 -0
- package/dist/src/core/field.d.ts.map +1 -1
- package/dist/src/core/types.d.ts +1 -1
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/export/build-static-raw-exports.d.ts +37 -0
- package/dist/src/export/build-static-raw-exports.d.ts.map +1 -0
- package/dist/src/export/write-static-raw-exports.d.ts +12 -0
- package/dist/src/export/write-static-raw-exports.d.ts.map +1 -0
- package/dist/src/history/record-revision.d.ts +2 -0
- package/dist/src/history/record-revision.d.ts.map +1 -1
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/storage/sqlite.d.ts.map +1 -1
- package/dist/src/storage/translations.d.ts +6 -0
- package/dist/src/storage/translations.d.ts.map +1 -1
- package/dist/src/translate/gemini-client.d.ts +7 -0
- package/dist/src/translate/gemini-client.d.ts.map +1 -1
- package/dist/src/translate/gemini-models.d.ts +8 -0
- package/dist/src/translate/gemini-models.d.ts.map +1 -0
- package/dist/src/translate/gemini-pricing.d.ts +11 -0
- package/dist/src/translate/gemini-pricing.d.ts.map +1 -0
- package/dist/src/translate/page-translator.d.ts +38 -1
- package/dist/src/translate/page-translator.d.ts.map +1 -1
- package/dist/src/translate/prompts/translation-prompt.d.ts +1 -2
- package/dist/src/translate/prompts/translation-prompt.d.ts.map +1 -1
- package/dist/src/translate/response-schema.d.ts +7 -0
- package/dist/src/translate/response-schema.d.ts.map +1 -0
- package/dist/src/translate/validate-translation.d.ts +14 -0
- package/dist/src/translate/validate-translation.d.ts.map +1 -0
- package/dist/src/translate/worklist.d.ts +3 -0
- package/dist/src/translate/worklist.d.ts.map +1 -1
- package/dist/src/validate/validate-project.d.ts.map +1 -1
- package/dist/studio/server.cjs +611 -194
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.d.ts +1 -1
- package/dist/studio/server.d.ts.map +1 -1
- package/dist/studio/server.js +611 -194
- package/dist/studio/server.js.map +1 -1
- package/package.json +16 -5
- package/bin/ensure-built.mjs +0 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hash/page-hash.ts","../../src/i18n/build-url.ts","../../src/core/builtin-fields.ts","../../src/core/field.ts","../../src/core/introspect-schema.ts","../../src/storage/sqlite.ts","../../src/storage/translations.ts","../../src/loader/normalize-en.ts","../../src/loader/create-loader.ts","../../src/translate/worklist.ts","../../studio/server.ts"],"names":["createHash","z","path","fs","Database","matter","Hono","serve"],"mappings":"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","file":"server.cjs","sourcesContent":["import { createHash } from \"node:crypto\";\n\n/** SHA-256 hex digest of a UTF-8 string. */\nexport function sha256(input: string): string {\n return createHash(\"sha256\").update(input, \"utf8\").digest(\"hex\");\n}\n\n/** Hash translatable frontmatter + body for translation staleness detection. */\nexport function computePageEnHash(\n translatableFrontmatter: Record<string, unknown>,\n body: string,\n): string {\n const payload = JSON.stringify({ frontmatter: translatableFrontmatter, body });\n return sha256(payload);\n}\n\n/** Hash MDX body content for revision tracking. */\nexport function computeBodyHash(body: string): string {\n return sha256(body);\n}\n","import type { ContentTypeConfig } from \"../core/types.js\";\n\nconst SLUG_PLACEHOLDER = \"{slug}\";\n\n/** Whether a content type has a public URL path template. */\nexport function isRoutableType(type: Pick<ContentTypeConfig, \"path\">): boolean {\n return typeof type.path === \"string\" && type.path.length > 0;\n}\n\n/** Validate path template at project init. */\nexport function assertValidPathTemplate(path: string, typeId: string): void {\n if (!path.startsWith(\"/\")) {\n throw new Error(`Content type \"${typeId}\": path must start with / (got \"${path}\")`);\n }\n const count = (path.match(/\\{slug\\}/g) ?? []).length;\n if (count !== 1) {\n throw new Error(\n `Content type \"${typeId}\": path must contain exactly one {slug} (got \"${path}\")`,\n );\n }\n}\n\n/** Segment before `{slug}` in the template, e.g. `/blog/` from `/blog/{slug}`. */\nexport function pathPrefix(template: string): string {\n const idx = template.indexOf(SLUG_PLACEHOLDER);\n if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);\n return template.slice(0, idx);\n}\n\n/** Segment after `{slug}` in the template, e.g. `/advanced` from `/blog/{slug}/advanced`. */\nexport function pathSuffix(template: string): string {\n const idx = template.indexOf(SLUG_PLACEHOLDER);\n if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);\n return template.slice(idx + SLUG_PLACEHOLDER.length);\n}\n\n/** Build a locale-aware pathname from a path template and slug. */\nexport function resolvePath(\n template: string,\n slug: string,\n locale: string,\n defaultLocale: string,\n): string {\n const relative = template.replace(SLUG_PLACEHOLDER, slug);\n if (locale === defaultLocale) return relative;\n return `/${locale}${relative}`;\n}\n\n/** Extract slug from a resolved path that matches the template. */\nexport function extractSlugFromResolvedPath(template: string, resolvedPath: string): string | null {\n const prefix = pathPrefix(template);\n const suffix = pathSuffix(template);\n if (!resolvedPath.startsWith(prefix)) return null;\n if (suffix && !resolvedPath.endsWith(suffix)) return null;\n const slugEnd = suffix ? resolvedPath.length - suffix.length : resolvedPath.length;\n const slug = resolvedPath.slice(prefix.length, slugEnd);\n return slug.length > 0 ? slug : null;\n}\n","import { z } from \"zod\";\nimport { extractSlugFromResolvedPath, pathPrefix, pathSuffix, resolvePath } from \"../i18n/build-url.js\";\nimport type { ContentTypeConfig, ScribeDocument } from \"./types.js\";\n\nexport const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport const slugPatternSchema = z\n .string()\n .regex(SLUG_PATTERN, \"slug must be lowercase-kebab-case\");\n\nexport const isoDateSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}(T[\\d:.Z+-]*)?$/, \"Use ISO date YYYY-MM-DD or full ISO 8601\");\n\nconst canonicalPathSchema = z.string().regex(/^\\//, \"canonicalPath must start with /\");\n\nexport interface BuiltinEnFields {\n aliases: string[];\n redirectTo?: string;\n publishedAt?: string;\n updatedAt?: string;\n noindex: boolean;\n /** Set only when explicitly provided in EN frontmatter. */\n canonicalPathOverride?: string;\n}\n\nexport interface BuiltinParseIssue {\n field: string;\n message: string;\n level: \"error\" | \"warning\";\n}\n\nconst LOCALE_BUILTIN_KEYS: Array<[string, string]> = [\n [\"publishedAt\", \"publishedAt is EN-only; inherited from the EN parent at load time\"],\n [\"updatedAt\", \"updatedAt is EN-only; inherited from the EN parent at load time\"],\n [\"noindex\", \"noindex is EN-only; inherited from the EN parent at load time\"],\n [\"canonicalPath\", \"canonicalPath is EN-only; inherited from the EN parent at load time\"],\n [\"aliases\", \"aliases is EN-only; remove from locale translation\"],\n [\"redirect_to\", \"redirect_to is EN-only; remove from locale translation\"],\n [\"translationOf\", \"translationOf is internal; remove from locale translation\"],\n [\"enSlug\", \"enSlug is internal; remove from locale translation\"],\n];\n\n/** Extract built-in EN frontmatter (aliases, dates, SEO) before Zod validation. */\nexport function extractBuiltinEnFields(\n data: Record<string, unknown>,\n pathTemplate: string | undefined,\n enSlug: string,\n defaultLocale: string,\n): {\n builtin: BuiltinEnFields;\n rest: Record<string, unknown>;\n issues: BuiltinParseIssue[];\n} {\n const issues: BuiltinParseIssue[] = [];\n const rest = { ...data };\n\n const aliasesResult = z.array(slugPatternSchema).max(20).optional().default([]).safeParse(rest.aliases ?? []);\n delete rest.aliases;\n\n const redirectRaw = rest.redirect_to;\n delete rest.redirect_to;\n\n let redirectTo: string | undefined;\n if (redirectRaw !== undefined && redirectRaw !== null && redirectRaw !== \"\") {\n if (typeof redirectRaw !== \"string\") {\n issues.push({\n field: \"redirect_to\",\n message: \"redirect_to must be a string path\",\n level: \"error\",\n });\n } else if (!pathTemplate) {\n issues.push({\n field: \"redirect_to\",\n message: \"redirect_to is not allowed on reference-only content types\",\n level: \"error\",\n });\n } else if (!extractSlugFromResolvedPath(pathTemplate, redirectRaw)) {\n issues.push({\n field: \"redirect_to\",\n message: `redirect_to must match path template \"${pathTemplate}\" (prefix \"${pathPrefix(pathTemplate)}\"${pathSuffix(pathTemplate) ? `, suffix \"${pathSuffix(pathTemplate)}\"` : \"\"})`,\n level: \"error\",\n });\n } else {\n redirectTo = redirectRaw;\n }\n }\n\n const aliases = aliasesResult.success ? aliasesResult.data : [];\n if (!aliasesResult.success) {\n for (const issue of aliasesResult.error.issues) {\n issues.push({\n field: `aliases.${issue.path.join(\".\")}`,\n message: issue.message,\n level: \"error\",\n });\n }\n }\n\n let publishedAt: string | undefined;\n if (rest.publishedAt !== undefined && rest.publishedAt !== null && rest.publishedAt !== \"\") {\n const parsed = isoDateSchema.safeParse(rest.publishedAt);\n if (parsed.success) {\n publishedAt = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"publishedAt\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.publishedAt;\n }\n\n let updatedAt: string | undefined;\n if (rest.updatedAt !== undefined && rest.updatedAt !== null && rest.updatedAt !== \"\") {\n const parsed = isoDateSchema.safeParse(rest.updatedAt);\n if (parsed.success) {\n updatedAt = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"updatedAt\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.updatedAt;\n } else if (publishedAt) {\n updatedAt = publishedAt;\n }\n\n let noindex = false;\n if (rest.noindex !== undefined && rest.noindex !== null && rest.noindex !== \"\") {\n if (typeof rest.noindex === \"boolean\") {\n noindex = rest.noindex;\n } else {\n issues.push({ field: \"noindex\", message: \"noindex must be a boolean\", level: \"error\" });\n }\n delete rest.noindex;\n }\n\n let canonicalPathOverride: string | undefined;\n if (rest.canonicalPath !== undefined && rest.canonicalPath !== null && rest.canonicalPath !== \"\") {\n const parsed = canonicalPathSchema.safeParse(rest.canonicalPath);\n if (parsed.success) {\n canonicalPathOverride = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"canonicalPath\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.canonicalPath;\n }\n\n for (const internalKey of [\"translationOf\", \"enSlug\"] as const) {\n if (rest[internalKey] !== undefined) {\n issues.push({\n field: internalKey,\n message: `${internalKey} is managed internally by Scribe; remove from frontmatter`,\n level: \"warning\",\n });\n delete rest[internalKey];\n }\n }\n\n return {\n builtin: {\n aliases,\n redirectTo,\n publishedAt,\n updatedAt,\n noindex,\n canonicalPathOverride,\n },\n rest,\n issues,\n };\n}\n\n/** Reject built-in keys on locale translation frontmatter. */\nexport function validateLocaleBuiltinFields(data: Record<string, unknown>): BuiltinParseIssue[] {\n const issues: BuiltinParseIssue[] = [];\n for (const [key, message] of LOCALE_BUILTIN_KEYS) {\n if (data[key] !== undefined) {\n issues.push({ field: key, message, level: \"error\" });\n }\n }\n return issues;\n}\n\n/** ISO date for sitemap lastmod from updatedAt or publishedAt. */\nexport function documentLastModified(doc: {\n updatedAt?: string;\n publishedAt?: string;\n}): string | undefined {\n const raw = doc.updatedAt ?? doc.publishedAt;\n if (!raw) return undefined;\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString();\n}\n\n/** Locale-aware pathname for a document. */\nexport function resolveCanonicalPathname(\n type: Pick<ContentTypeConfig, \"path\">,\n doc: Pick<ScribeDocument, \"slug\" | \"locale\" | \"canonicalPathOverride\">,\n defaultLocale: string,\n): string {\n if (doc.canonicalPathOverride) {\n if (doc.locale === defaultLocale) return doc.canonicalPathOverride;\n return `/${doc.locale}${doc.canonicalPathOverride}`;\n }\n if (!type.path) return `/${doc.slug}`;\n return resolvePath(type.path, doc.slug, doc.locale, defaultLocale);\n}\n\n/** Hydrate locale frontmatter with EN-only built-in fields at load time. */\nexport function mergeBuiltinsIntoFrontmatter(\n frontmatter: Record<string, unknown>,\n doc: Pick<\n ScribeDocument,\n \"publishedAt\" | \"updatedAt\" | \"noindex\" | \"canonicalPathOverride\" | \"slug\" | \"locale\"\n >,\n type: Pick<ContentTypeConfig, \"path\">,\n defaultLocale: string,\n): Record<string, unknown> {\n const out = { ...frontmatter };\n if (doc.publishedAt !== undefined) out.publishedAt = doc.publishedAt;\n if (doc.updatedAt !== undefined) out.updatedAt = doc.updatedAt;\n out.noindex = doc.noindex;\n out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale);\n return out;\n}\n\nexport function seoFieldsFromEn(enDoc: ScribeDocument): Pick<\n ScribeDocument,\n \"publishedAt\" | \"updatedAt\" | \"noindex\" | \"canonicalPathOverride\" | \"redirectTo\"\n> {\n return {\n publishedAt: enDoc.publishedAt,\n updatedAt: enDoc.updatedAt,\n noindex: enDoc.noindex,\n canonicalPathOverride: enDoc.canonicalPathOverride,\n redirectTo: enDoc.redirectTo,\n };\n}\n","import { z } from \"zod\";\nimport type { z as Zod } from \"zod\";\n\nconst FIELD_KIND = Symbol.for(\"@genlook/scribe/fieldKind\");\nconst RELATION_META = Symbol.for(\"@genlook/scribe/relationMeta\");\n\nexport type FieldKind = \"translatable\" | \"structural\";\n\nexport interface RelationMeta {\n typeId: string;\n multiple: boolean;\n optional: boolean;\n}\n\n/**\n * Type-level brand carried by `field.relation()` schemas so the target\n * content-type id (and multiplicity/optionality) survive into `related()`.\n * Never exists at runtime.\n */\nexport declare const RELATION_BRAND: unique symbol;\n\nexport interface RelationBrand<\n TTarget extends string = string,\n TMultiple extends boolean = boolean,\n TOptional extends boolean = boolean,\n> {\n target: TTarget;\n multiple: TMultiple;\n optional: TOptional;\n}\n\n/** A Zod schema branded with relation metadata (see `field.relation()`). */\nexport type RelationField<\n TZod extends Zod.ZodTypeAny,\n TBrand extends RelationBrand,\n> = TZod & { [RELATION_BRAND]: TBrand };\n\n/** Return whether a Zod field is translatable or structural. */\nexport function getFieldKind(schema: Zod.ZodTypeAny): FieldKind {\n const tagged = schema as Zod.ZodTypeAny & { [FIELD_KIND]?: FieldKind };\n return tagged[FIELD_KIND] ?? \"structural\";\n}\n\n/** Return relation metadata if the field was created with `field.relation()`. */\nexport function getRelationTarget(schema: Zod.ZodTypeAny): RelationMeta | null {\n let current: Zod.ZodTypeAny = schema;\n for (let i = 0; i < 8; i++) {\n const tagged = current as Zod.ZodTypeAny & {\n [RELATION_META]?: RelationMeta;\n unwrap?: () => Zod.ZodTypeAny;\n removeDefault?: () => Zod.ZodTypeAny;\n _def?: { innerType?: Zod.ZodTypeAny };\n };\n if (tagged[RELATION_META]) {\n return tagged[RELATION_META];\n }\n if (typeof tagged.unwrap === \"function\") {\n current = tagged.unwrap();\n continue;\n }\n if (typeof tagged.removeDefault === \"function\") {\n current = tagged.removeDefault();\n continue;\n }\n if (tagged._def?.innerType) {\n current = tagged._def.innerType;\n continue;\n }\n break;\n }\n return null;\n}\n\nfunction mark<T extends Zod.ZodTypeAny>(schema: T, kind: FieldKind): T {\n Object.defineProperty(schema, FIELD_KIND, {\n value: kind,\n enumerable: false,\n configurable: true,\n });\n return schema;\n}\n\nfunction markRelation<T extends Zod.ZodTypeAny>(schema: T, meta: RelationMeta): T {\n Object.defineProperty(schema, RELATION_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n });\n return mark(schema, \"structural\");\n}\n\n/**\n * Options for `field.relation()`. Constraints live here (not as chained Zod\n * methods) because chaining clones the schema and would drop the relation\n * metadata.\n */\nexport interface RelationFieldOptions {\n /** The field holds an array of slugs instead of a single slug. */\n multiple?: boolean;\n /** The field may be omitted; `related()` then returns `null` (single) or `[]` (multiple). */\n optional?: boolean;\n /** Minimum item count (`multiple: true` only). */\n min?: number;\n /** Maximum item count (`multiple: true` only). */\n max?: number;\n}\n\ntype Bool<T> = [T] extends [true] ? true : false;\n\ntype RelationZod<TOpts extends RelationFieldOptions> =\n Bool<TOpts[\"optional\"]> extends true\n ? Zod.ZodOptional<\n Bool<TOpts[\"multiple\"]> extends true ? Zod.ZodArray<Zod.ZodString> : Zod.ZodString\n >\n : Bool<TOpts[\"multiple\"]> extends true\n ? Zod.ZodArray<Zod.ZodString>\n : Zod.ZodString;\n\ntype RelationFieldFor<\n TTarget extends string,\n TOpts extends RelationFieldOptions,\n> = RelationField<\n RelationZod<TOpts>,\n RelationBrand<TTarget, Bool<TOpts[\"multiple\"]>, Bool<TOpts[\"optional\"]>>\n>;\n\n/**\n * Mark Zod fields for Scribe:\n * - `translatable(schema)` — sent to the translator per locale.\n * - `structural(schema)` — EN-only; merged from EN into every locale document.\n * - `relation(typeId, options?)` — EN slug reference(s) to another content type,\n * validated by `scribe validate` and dereferenced via `scribe.<type>.related()`.\n */\nexport const field = {\n translatable: <T extends Zod.ZodTypeAny>(schema: T): T => mark(schema, \"translatable\"),\n structural: <T extends Zod.ZodTypeAny>(schema: T): T => mark(schema, \"structural\"),\n relation: <const TTarget extends string, const TOpts extends RelationFieldOptions = {}>(\n typeId: TTarget,\n options?: TOpts,\n ): RelationFieldFor<TTarget, TOpts> => {\n const multiple = options?.multiple ?? false;\n const optional = options?.optional ?? false;\n if ((options?.min !== undefined || options?.max !== undefined) && !multiple) {\n throw new Error(\n `field.relation(\"${typeId}\"): min/max require { multiple: true }`,\n );\n }\n let inner: Zod.ZodTypeAny;\n if (multiple) {\n let arr = z.array(z.string().min(1));\n if (options?.min !== undefined) arr = arr.min(options.min);\n if (options?.max !== undefined) arr = arr.max(options.max);\n inner = arr;\n } else {\n inner = z.string().min(1);\n }\n markRelation(inner, { typeId, multiple, optional });\n const schema = optional ? inner.optional() : inner;\n return schema as RelationFieldFor<TTarget, TOpts>;\n },\n};\n\n/** Strip Zod wrappers (optional, default, etc.) to reach the inner schema. */\nexport function unwrapSchema(schema: Zod.ZodTypeAny): Zod.ZodTypeAny {\n let current: Zod.ZodTypeAny = schema;\n for (let i = 0; i < 8; i++) {\n const anySchema = current as Zod.ZodTypeAny & {\n unwrap?: () => Zod.ZodTypeAny;\n removeDefault?: () => Zod.ZodTypeAny;\n _def?: { innerType?: Zod.ZodTypeAny; type?: string };\n };\n if (typeof anySchema.unwrap === \"function\") {\n current = anySchema.unwrap();\n continue;\n }\n if (typeof anySchema.removeDefault === \"function\") {\n current = anySchema.removeDefault();\n continue;\n }\n if (anySchema._def?.innerType) {\n current = anySchema._def.innerType;\n continue;\n }\n break;\n }\n return current;\n}\n","import type { z } from \"zod\";\nimport { getFieldKind, getRelationTarget, unwrapSchema } from \"./field.js\";\n\nexport interface SchemaFieldMeta {\n path: string[];\n kind: \"translatable\" | \"structural\" | \"relation\";\n relationTarget?: string;\n relationMultiple?: boolean;\n relationOptional?: boolean;\n}\n\n/** List schema fields with translatable/structural/relation metadata. */\nexport function introspectSchema(schema: z.ZodTypeAny, prefix: string[] = []): SchemaFieldMeta[] {\n const relation = getRelationTarget(schema);\n if (relation && prefix.length > 0) {\n return [\n {\n path: prefix,\n kind: \"relation\",\n relationTarget: relation.typeId,\n relationMultiple: relation.multiple,\n relationOptional: relation.optional,\n },\n ];\n }\n\n const base = unwrapSchema(schema);\n if (base instanceof Object && \"shape\" in base) {\n const shape = (base as z.ZodObject<z.ZodRawShape>).shape;\n const fields: SchemaFieldMeta[] = [];\n for (const [key, child] of Object.entries(shape)) {\n fields.push(...introspectSchema(child as z.ZodTypeAny, [...prefix, key]));\n }\n return fields;\n }\n\n if (base instanceof Object && \"element\" in base) {\n const element = (base as z.ZodArray<z.ZodTypeAny>).element;\n const elementBase = unwrapSchema(element);\n if (elementBase instanceof Object && \"shape\" in elementBase) {\n const shape = (elementBase as z.ZodObject<z.ZodRawShape>).shape;\n const fields: SchemaFieldMeta[] = [];\n for (const [key, child] of Object.entries(shape)) {\n fields.push(...introspectSchema(child as z.ZodTypeAny, [...prefix, \"*\", key]));\n }\n return fields;\n }\n }\n\n return [{ path: prefix, kind: getFieldKind(schema) }];\n}\n\nexport function extractByPaths(\n data: Record<string, unknown>,\n paths: string[][],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const path of paths) {\n const value = getAtPath(data, path);\n if (value !== undefined) {\n setAtPath(out, path.filter((p) => p !== \"*\"), value);\n }\n }\n return out;\n}\n\n/** Extract frontmatter fields marked as translatable. */\nexport function pickTranslatable(data: Record<string, unknown>, schema: z.ZodTypeAny): Record<string, unknown> {\n const translatablePaths = introspectSchema(schema)\n .filter((f) => f.kind === \"translatable\")\n .map((f) => f.path);\n return extractByPaths(data, translatablePaths);\n}\n\n/** Extract frontmatter fields marked as structural (EN-only). */\nexport function pickStructural(data: Record<string, unknown>, schema: z.ZodTypeAny): Record<string, unknown> {\n const structuralPaths = introspectSchema(schema)\n .filter((f) => f.kind === \"structural\" || f.kind === \"relation\")\n .map((f) => f.path);\n return extractByPaths(data, structuralPaths);\n}\n\n/** Merge EN structural fields onto a locale document's frontmatter at load time. */\nexport function mergeStructuralOntoLocale(\n localeData: Record<string, unknown>,\n enData: Record<string, unknown>,\n schema: z.ZodTypeAny,\n): Record<string, unknown> {\n const structural = pickStructural(enData, schema);\n const translatable = pickTranslatable(localeData, schema);\n return deepMerge(structural, translatable);\n}\n\nfunction getAtPath(obj: Record<string, unknown>, path: string[]): unknown {\n let current: unknown = obj;\n for (const segment of path) {\n if (segment === \"*\") {\n if (!Array.isArray(current)) return undefined;\n return current.map((item) =>\n typeof item === \"object\" && item !== null\n ? getAtPath(item as Record<string, unknown>, path.slice(path.indexOf(\"*\") + 1))\n : undefined,\n );\n }\n if (typeof current !== \"object\" || current === null || Array.isArray(current)) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nfunction setAtPath(obj: Record<string, unknown>, path: string[], value: unknown): void {\n if (path.length === 0) return;\n if (path.length === 1) {\n obj[path[0]!] = value;\n return;\n }\n const [head, ...rest] = path;\n if (!(head! in obj) || typeof obj[head!] !== \"object\" || obj[head!] === null) {\n obj[head!] = {};\n }\n setAtPath(obj[head!] as Record<string, unknown>, rest, value);\n}\n\nfunction deepMerge(base: Record<string, unknown>, overlay: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(overlay)) {\n if (\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n out[key] &&\n typeof out[key] === \"object\" &&\n !Array.isArray(out[key])\n ) {\n out[key] = deepMerge(out[key] as Record<string, unknown>, value as Record<string, unknown>);\n } else if (Array.isArray(value) && Array.isArray(out[key])) {\n out[key] = mergeArrayOverlay(out[key] as unknown[], value as unknown[]);\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n\nfunction mergeArrayOverlay(base: unknown[], overlay: unknown[]): unknown[] {\n return base.map((item, index) => {\n const overlayItem = overlay[index];\n if (\n item &&\n typeof item === \"object\" &&\n !Array.isArray(item) &&\n overlayItem &&\n typeof overlayItem === \"object\" &&\n !Array.isArray(overlayItem)\n ) {\n return deepMerge(item as Record<string, unknown>, overlayItem as Record<string, unknown>);\n }\n return overlayItem ?? item;\n });\n}\n\n/** Collect relation field paths and targets from a content schema. */\nexport function listRelationFields(schema: z.ZodTypeAny): SchemaFieldMeta[] {\n return introspectSchema(schema).filter((f) => f.kind === \"relation\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { ScribeConfig } from \"../core/types.js\";\n\nconst SCHEMA_VERSION = 2;\n\nconst MIGRATIONS: string[] = [\n `CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS translations (\n content_type TEXT NOT NULL,\n en_slug TEXT NOT NULL,\n locale TEXT NOT NULL,\n slug TEXT NOT NULL,\n frontmatter_json TEXT NOT NULL,\n body TEXT NOT NULL,\n en_hash TEXT NOT NULL,\n translated_at TEXT NOT NULL,\n model TEXT NOT NULL,\n PRIMARY KEY (content_type, en_slug, locale)\n )`,\n `CREATE INDEX IF NOT EXISTS idx_translations_type_locale\n ON translations(content_type, locale)`,\n `CREATE TABLE IF NOT EXISTS revisions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n content_type TEXT NOT NULL,\n en_slug TEXT NOT NULL,\n locale TEXT,\n revision_kind TEXT NOT NULL,\n en_hash TEXT NOT NULL,\n body_hash TEXT NOT NULL,\n created_at TEXT NOT NULL,\n model TEXT,\n body_preview TEXT\n )`,\n `CREATE INDEX IF NOT EXISTS idx_revisions_lookup\n ON revisions(content_type, en_slug, locale, created_at DESC)`,\n `CREATE TABLE IF NOT EXISTS slug_aliases (\n content_type TEXT NOT NULL,\n canonical_en_slug TEXT NOT NULL,\n alias_en_slug TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (content_type, alias_en_slug)\n )`,\n `CREATE INDEX IF NOT EXISTS idx_slug_aliases_canonical\n ON slug_aliases(content_type, canonical_en_slug)`,\n `CREATE TABLE IF NOT EXISTS alias_locale_slugs (\n content_type TEXT NOT NULL,\n alias_en_slug TEXT NOT NULL,\n locale TEXT NOT NULL,\n locale_slug TEXT NOT NULL,\n captured_at TEXT NOT NULL,\n PRIMARY KEY (content_type, alias_en_slug, locale)\n )`,\n];\n\nexport type SqliteMode = \"readonly\" | \"readwrite\";\n\n/** Absolute path to the SQLite translation store (precomputed by `resolveConfig`). */\nexport function resolveStorePath(config: ScribeConfig): string {\n return config.storePath;\n}\n\n/** Open the SQLite translation store (creates schema if missing). */\nexport function openStore(config: ScribeConfig, mode: SqliteMode = \"readwrite\"): Database.Database {\n const storePath = resolveStorePath(config);\n fs.mkdirSync(path.dirname(storePath), { recursive: true });\n const db = new Database(storePath, { readonly: mode === \"readonly\" });\n if (mode === \"readwrite\") {\n migrate(db);\n }\n return db;\n}\n\nfunction migrate(db: Database.Database): void {\n for (const sql of MIGRATIONS) {\n db.exec(sql);\n }\n db.prepare(\n `INSERT INTO meta(key, value) VALUES('schema_version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n ).run(String(SCHEMA_VERSION));\n}\n\nexport function closeStore(db: Database.Database): void {\n db.close();\n}\n","import type Database from \"better-sqlite3\";\n\nexport interface TranslationRow {\n content_type: string;\n en_slug: string;\n locale: string;\n slug: string;\n frontmatter_json: string;\n body: string;\n en_hash: string;\n translated_at: string;\n model: string;\n}\n\nexport interface TranslationInput {\n contentType: string;\n enSlug: string;\n locale: string;\n slug: string;\n frontmatter: Record<string, unknown>;\n body: string;\n enHash: string;\n translatedAt: string;\n model: string;\n}\n\nexport interface RevisionInput {\n contentType: string;\n enSlug: string;\n locale: string | null;\n revisionKind: \"translation\" | \"en_edit_detected\" | \"snapshot\";\n enHash: string;\n bodyHash: string;\n createdAt: string;\n model?: string;\n bodyPreview?: string;\n}\n\nexport interface RevisionRow {\n id: number;\n content_type: string;\n en_slug: string;\n locale: string | null;\n revision_kind: string;\n en_hash: string;\n body_hash: string;\n created_at: string;\n model: string | null;\n body_preview: string | null;\n}\n\nexport function upsertTranslation(db: Database.Database, input: TranslationInput): void {\n db.prepare(\n `INSERT INTO translations (\n content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(content_type, en_slug, locale) DO UPDATE SET\n slug = excluded.slug,\n frontmatter_json = excluded.frontmatter_json,\n body = excluded.body,\n en_hash = excluded.en_hash,\n translated_at = excluded.translated_at,\n model = excluded.model`,\n ).run(\n input.contentType,\n input.enSlug,\n input.locale,\n input.slug,\n JSON.stringify(input.frontmatter),\n input.body,\n input.enHash,\n input.translatedAt,\n input.model,\n );\n}\n\nexport function getTranslation(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n locale: string,\n): TranslationRow | undefined {\n return db\n .prepare(\n `SELECT * FROM translations WHERE content_type = ? AND en_slug = ? AND locale = ?`,\n )\n .get(contentType, enSlug, locale) as TranslationRow | undefined;\n}\n\nexport function listTranslationsForType(\n db: Database.Database,\n contentType: string,\n): TranslationRow[] {\n return db\n .prepare(`SELECT * FROM translations WHERE content_type = ? ORDER BY en_slug, locale`)\n .all(contentType) as TranslationRow[];\n}\n\nexport function listTranslationsForEnSlug(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n): TranslationRow[] {\n return db\n .prepare(\n `SELECT * FROM translations WHERE content_type = ? AND en_slug = ? ORDER BY locale`,\n )\n .all(contentType, enSlug) as TranslationRow[];\n}\n\nexport function listTranslationsForLocale(\n db: Database.Database,\n contentType: string,\n locale: string,\n): TranslationRow[] {\n return db\n .prepare(`SELECT * FROM translations WHERE content_type = ? AND locale = ? ORDER BY en_slug`)\n .all(contentType, locale) as TranslationRow[];\n}\n\nexport function bulkLoadTranslations(db: Database.Database): TranslationRow[] {\n return db.prepare(`SELECT * FROM translations ORDER BY content_type, en_slug, locale`).all() as TranslationRow[];\n}\n\nexport function appendRevision(db: Database.Database, input: RevisionInput): number {\n const result = db\n .prepare(\n `INSERT INTO revisions (\n content_type, en_slug, locale, revision_kind, en_hash, body_hash, created_at, model, body_preview\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n input.contentType,\n input.enSlug,\n input.locale,\n input.revisionKind,\n input.enHash,\n input.bodyHash,\n input.createdAt,\n input.model ?? null,\n input.bodyPreview ?? null,\n );\n return Number(result.lastInsertRowid);\n}\n\n/** List revision history for an EN slug, optionally filtered by locale. */\nexport function listRevisions(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n locale?: string,\n): RevisionRow[] {\n if (locale) {\n return db\n .prepare(\n `SELECT * FROM revisions\n WHERE content_type = ? AND en_slug = ? AND locale = ?\n ORDER BY created_at DESC, id DESC`,\n )\n .all(contentType, enSlug, locale) as RevisionRow[];\n }\n return db\n .prepare(\n `SELECT * FROM revisions\n WHERE content_type = ? AND en_slug = ?\n ORDER BY created_at DESC, id DESC`,\n )\n .all(contentType, enSlug) as RevisionRow[];\n}\n\nexport function countTranslations(db: Database.Database): number {\n const row = db.prepare(`SELECT COUNT(*) as count FROM translations`).get() as { count: number };\n return row.count;\n}\n\nexport function countStaleTranslations(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n currentEnHash: string,\n): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) as count FROM translations\n WHERE content_type = ? AND en_slug = ? AND en_hash != ?`,\n )\n .get(contentType, enSlug, currentEnHash) as { count: number };\n return row.count;\n}\n","export function normalizeEnFrontmatter(data: Record<string, unknown>): Record<string, unknown> {\n const out = { ...data };\n if (!out.publishedAt && typeof out.date === \"string\") {\n out.publishedAt = out.date;\n }\n if (!out.heroImage && typeof out.image === \"string\" && out.image.startsWith(\"/\")) {\n out.heroImage = out.image;\n }\n if (!out.updatedAt && typeof out.publishedAt === \"string\") {\n out.updatedAt = out.publishedAt;\n }\n return out;\n}\n\nexport function isPublishableContentFile(name: string): boolean {\n if (!name.endsWith(\".md\") && !name.endsWith(\".mdx\")) return false;\n const first = name.charAt(0);\n return first === first.toLowerCase() && first !== \"_\";\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport type { z } from \"zod\";\nimport {\n extractBuiltinEnFields,\n mergeBuiltinsIntoFrontmatter,\n seoFieldsFromEn,\n} from \"../core/builtin-fields.js\";\nimport { mergeStructuralOntoLocale, pickTranslatable } from \"../core/introspect-schema.js\";\nimport type {\n AllDocuments,\n ContentTypeConfig,\n LocaleIndex,\n ScribeConfig,\n ScribeDocument,\n} from \"../core/types.js\";\nimport { openStore, resolveStorePath } from \"../storage/sqlite.js\";\nimport { listTranslationsForType } from \"../storage/translations.js\";\nimport { isPublishableContentFile, normalizeEnFrontmatter } from \"./normalize-en.js\";\n\nfunction isPostFile(name: string): boolean {\n return isPublishableContentFile(name);\n}\n\nfunction listEnFiles(contentDir: string): string[] {\n if (!fs.existsSync(contentDir)) return [];\n return fs\n .readdirSync(contentDir)\n .filter(isPostFile)\n .map((f) => path.join(contentDir, f));\n}\n\nfunction slugFromPath(filePath: string): string {\n return path.basename(filePath).replace(/\\.(md|mdx)$/, \"\");\n}\n\nexport interface ParseEnResult {\n document: ScribeDocument | null;\n issues: Array<{ field: string; message: string; level: \"error\" | \"warning\" }>;\n}\n\nexport function parseEnMdx(\n filePath: string,\n config: ScribeConfig,\n type: ContentTypeConfig,\n): ParseEnResult {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = matter(raw);\n const slug = slugFromPath(filePath);\n const normalized = normalizeEnFrontmatter(parsed.data as Record<string, unknown>);\n const { builtin, rest, issues: builtinIssues } = extractBuiltinEnFields(\n normalized,\n type.path,\n slug,\n config.defaultLocale,\n );\n const issues = builtinIssues.map((issue) => ({\n field: issue.field,\n message: issue.message,\n level: issue.level,\n }));\n\n const result = type.schema.safeParse(rest);\n if (!result.success) {\n return {\n document: null,\n issues: [\n ...issues,\n ...result.error.issues.map((issue) => ({\n field: issue.path.join(\".\"),\n message: issue.message,\n level: \"error\" as const,\n })),\n ],\n };\n }\n\n if (issues.some((i) => i.level === \"error\")) {\n return { document: null, issues };\n }\n\n const frontmatter = mergeBuiltinsIntoFrontmatter(\n result.data as Record<string, unknown>,\n {\n publishedAt: builtin.publishedAt,\n updatedAt: builtin.updatedAt,\n noindex: builtin.noindex,\n canonicalPathOverride: builtin.canonicalPathOverride,\n slug,\n locale: config.defaultLocale,\n },\n type,\n config.defaultLocale,\n );\n\n const crossIssues = type.crossValidate?.(result.data as z.infer<typeof type.schema>, {\n locale: config.defaultLocale,\n defaultLocale: config.defaultLocale,\n slug,\n enSlug: slug,\n knownLocales: config.locales,\n }) ?? [];\n issues.push(...crossIssues);\n\n const document: ScribeDocument = {\n slug,\n enSlug: slug,\n locale: config.defaultLocale,\n aliases: builtin.aliases,\n redirectTo: builtin.redirectTo,\n publishedAt: builtin.publishedAt,\n updatedAt: builtin.updatedAt,\n noindex: builtin.noindex,\n canonicalPathOverride: builtin.canonicalPathOverride,\n frontmatter,\n content: parsed.content,\n filePath,\n };\n\n return { document, issues };\n}\n\nfunction buildDocumentFromTranslation(\n row: {\n slug: string;\n en_slug: string;\n locale: string;\n frontmatter_json: string;\n body: string;\n },\n enDoc: ScribeDocument,\n type: ContentTypeConfig,\n): ScribeDocument {\n const localeFm = JSON.parse(row.frontmatter_json) as Record<string, unknown>;\n const merged = mergeStructuralOntoLocale(localeFm, enDoc.frontmatter, type.schema);\n const seo = seoFieldsFromEn(enDoc);\n const frontmatter = mergeBuiltinsIntoFrontmatter(\n merged,\n { ...seo, slug: row.slug, locale: row.locale },\n type,\n enDoc.locale,\n );\n\n return {\n slug: row.slug,\n enSlug: row.en_slug,\n locale: row.locale,\n aliases: [],\n redirectTo: seo.redirectTo,\n publishedAt: seo.publishedAt,\n updatedAt: seo.updatedAt,\n noindex: seo.noindex,\n canonicalPathOverride: seo.canonicalPathOverride,\n frontmatter,\n content: row.body,\n };\n}\n\nconst DEV_REVALIDATE_MS = 1500;\n\nexport function createContentLoader(config: ScribeConfig, type: ContentTypeConfig): () => AllDocuments {\n let cached: AllDocuments | null = null;\n let signature = \"\";\n let lastCheck = 0;\n const contentDir = path.join(/* turbopackIgnore: true */ config.rootDir, type.contentDir);\n const storePath = resolveStorePath(config);\n const isProd = process.env.NODE_ENV === \"production\";\n\n function computeSignature(): string {\n const files = listEnFiles(contentDir);\n let newest = 0;\n for (const f of files) {\n try {\n newest = Math.max(newest, fs.statSync(f).mtimeMs);\n } catch {\n /* ignore */\n }\n }\n let store = 0;\n try {\n store = fs.statSync(storePath).mtimeMs;\n } catch {\n /* ignore */\n }\n return `${files.length}:${newest}:${store}`;\n }\n\n function build(): AllDocuments {\n const out = new Map<string, LocaleIndex>();\n const englishBySlug = new Map<string, ScribeDocument>();\n\n for (const file of listEnFiles(contentDir)) {\n const { document, issues } = parseEnMdx(file, config, type);\n if (document) {\n englishBySlug.set(document.slug, document);\n if (issues.length > 0) {\n for (const issue of issues) {\n console.warn(\n `[scribe:${type.id}] ${file} ${issue.level}: ${issue.field}: ${issue.message}`,\n );\n }\n }\n } else {\n console.warn(\n `[scribe:${type.id}] Skipping ${file} — validation failed:\\n` +\n issues.map((i) => ` - ${i.field}: ${i.message}`).join(\"\\n\"),\n );\n }\n }\n\n out.set(config.defaultLocale, {\n bySlug: englishBySlug,\n byEnSlug: englishBySlug,\n });\n\n const db = openStore(config, \"readonly\");\n const rows = listTranslationsForType(db, type.id);\n db.close();\n\n const rowsByLocale = new Map<string, typeof rows>();\n for (const row of rows) {\n const list = rowsByLocale.get(row.locale) ?? [];\n list.push(row);\n rowsByLocale.set(row.locale, list);\n }\n\n for (const locale of config.locales) {\n if (locale === config.defaultLocale) continue;\n const bySlug = new Map<string, ScribeDocument>();\n const byEnSlug = new Map<string, ScribeDocument>();\n for (const row of rowsByLocale.get(locale) ?? []) {\n const enDoc = englishBySlug.get(row.en_slug);\n if (!enDoc) continue;\n const doc = buildDocumentFromTranslation(row, enDoc, type);\n bySlug.set(doc.slug, doc);\n byEnSlug.set(row.en_slug, doc);\n }\n out.set(locale, { bySlug, byEnSlug });\n }\n\n return out;\n }\n\n return () => {\n if (cached) {\n if (isProd) return cached;\n const now = Date.now();\n if (now - lastCheck < DEV_REVALIDATE_MS) return cached;\n lastCheck = now;\n const sig = computeSignature();\n if (sig === signature) return cached;\n cached = build();\n signature = sig;\n return cached;\n }\n lastCheck = Date.now();\n cached = build();\n signature = isProd ? \"\" : computeSignature();\n return cached;\n };\n}\n\nexport function readEnDocument(\n config: ScribeConfig,\n type: ContentTypeConfig,\n enSlug: string,\n): ScribeDocument | null {\n const contentDir = path.join(/* turbopackIgnore: true */ config.rootDir, type.contentDir);\n for (const ext of [\".mdx\", \".md\"]) {\n const filePath = path.join(contentDir, `${enSlug}${ext}`);\n if (!fs.existsSync(filePath)) continue;\n const { document } = parseEnMdx(filePath, config, type);\n return document;\n }\n return null;\n}\n\nexport function getTranslatablePayload(\n doc: ScribeDocument,\n type: ContentTypeConfig,\n): { frontmatter: Record<string, unknown>; body: string } {\n return {\n frontmatter: pickTranslatable(doc.frontmatter, type.schema),\n body: doc.content,\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ScribeConfig } from \"../core/types.js\";\nimport { isPublishableContentFile } from \"../loader/normalize-en.js\";\nimport { computePageEnHash } from \"../hash/page-hash.js\";\nimport { getTranslatablePayload, readEnDocument } from \"../loader/create-loader.js\";\nimport { openStore } from \"../storage/sqlite.js\";\nimport { getTranslation } from \"../storage/translations.js\";\n\nexport interface TranslationWorkItem {\n contentType: string;\n enSlug: string;\n locale: string;\n reason: \"missing\" | \"stale\";\n currentEnHash: string;\n storedEnHash?: string;\n}\n\nexport interface WorklistOptions {\n contentType?: string;\n locales?: string[];\n enSlug?: string;\n}\n\nfunction listEnSlugs(rootDir: string, contentDir: string): string[] {\n const dir = path.join(rootDir, contentDir);\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter(isPublishableContentFile)\n .map((f) => f.replace(/\\.(md|mdx)$/, \"\"));\n}\n\n/** List locale pages that are missing or stale vs current EN content. */\nexport function buildWorklist(config: ScribeConfig, options: WorklistOptions = {}): TranslationWorkItem[] {\n const db = openStore(config, \"readonly\");\n const items: TranslationWorkItem[] = [];\n const locales =\n options.locales ??\n config.locales.filter((locale) => locale !== config.defaultLocale);\n\n for (const type of config.types) {\n if (options.contentType && type.id !== options.contentType) continue;\n const enSlugs = options.enSlug ? [options.enSlug] : listEnSlugs(config.rootDir, type.contentDir);\n\n for (const enSlug of enSlugs) {\n const enDoc = readEnDocument(config, type, enSlug);\n if (!enDoc) continue;\n const payload = getTranslatablePayload(enDoc, type);\n const currentEnHash = computePageEnHash(payload.frontmatter, payload.body);\n\n for (const locale of locales) {\n if (locale === config.defaultLocale) continue;\n const existing = getTranslation(db, type.id, enSlug, locale);\n if (!existing) {\n items.push({\n contentType: type.id,\n enSlug,\n locale,\n reason: \"missing\",\n currentEnHash,\n });\n continue;\n }\n if (existing.en_hash !== currentEnHash) {\n items.push({\n contentType: type.id,\n enSlug,\n locale,\n reason: \"stale\",\n currentEnHash,\n storedEnHash: existing.en_hash,\n });\n }\n }\n }\n }\n\n db.close();\n return items;\n}\n\n/** Resolve target locales from CLI flags or a named preset. */\nexport function resolveLocalesFromPreset(\n config: ScribeConfig,\n preset?: string,\n explicitLocales?: string[],\n): string[] {\n if (explicitLocales?.length) return explicitLocales;\n if (preset && config.localePresets?.[preset]) {\n return config.localePresets[preset]!.filter((l) => l !== config.defaultLocale);\n }\n return config.locales.filter((l) => l !== config.defaultLocale);\n}\n","import { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport type { ScribeProject } from \"../src/core/types.js\";\nimport { computePageEnHash } from \"../src/hash/page-hash.js\";\nimport { getTranslatablePayload, readEnDocument } from \"../src/loader/create-loader.js\";\nimport { openStore } from \"../src/storage/sqlite.js\";\nimport { listRevisions, listTranslationsForType } from \"../src/storage/translations.js\";\nimport { buildWorklist } from \"../src/translate/worklist.js\";\n\nfunction renderLayout(title: string, body: string): string {\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${title} — Scribe Studio</title>\n <style>\n body { font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; background: #0b0d10; color: #e8eaed; }\n header { padding: 16px 24px; border-bottom: 1px solid #222; display: flex; gap: 16px; }\n header a { color: #9ecbff; text-decoration: none; }\n main { padding: 24px; }\n table { border-collapse: collapse; width: 100%; }\n th, td { border: 1px solid #333; padding: 8px 10px; text-align: left; vertical-align: top; }\n th { background: #151922; }\n .muted { color: #9aa0a6; }\n .stale { color: #ffb4a2; }\n .ok { color: #8ce99a; }\n .card { background: #151922; border: 1px solid #333; border-radius: 8px; padding: 16px; margin-bottom: 16px; }\n </style>\n</head>\n<body>\n <header>\n <strong>Scribe Studio</strong>\n <a href=\"/\">Browser</a>\n <a href=\"/staleness\">Staleness</a>\n <a href=\"/history\">History</a>\n </header>\n <main>${body}</main>\n</body>\n</html>`;\n}\n\n/** Start a local read-only Scribe studio (browser, staleness, history). */\nexport async function startStudio(\n project: ScribeProject,\n options: { port?: number; host?: string } = {},\n): Promise<void> {\n const app = new Hono();\n const config = project.config;\n\n app.get(\"/\", (c) => {\n const cards = project.listTypes().map((type) => {\n const localeRows = config.locales\n .map((locale) => {\n const count = type.load().get(locale)?.bySlug.size ?? 0;\n return `<li>${locale}: ${count}</li>`;\n })\n .join(\"\");\n return `<div class=\"card\"><h2>${type.config.label}</h2><ul>${localeRows}</ul></div>`;\n });\n return c.html(renderLayout(\"Browser\", cards.join(\"\")));\n });\n\n app.get(\"/staleness\", (c) => {\n const worklist = buildWorklist(config);\n const rows = worklist\n .slice(0, 500)\n .map(\n (item) =>\n `<tr><td>${item.contentType}</td><td>${item.enSlug}</td><td>${item.locale}</td><td class=\"stale\">${item.reason}</td></tr>`,\n )\n .join(\"\");\n const html = `<h1>Translation staleness</h1><p class=\"muted\">${worklist.length} stale/missing entries (showing up to 500)</p>\n <table><thead><tr><th>Type</th><th>EN slug</th><th>Locale</th><th>Status</th></tr></thead><tbody>${rows}</tbody></table>`;\n return c.html(renderLayout(\"Staleness\", html));\n });\n\n app.get(\"/history\", (c) => {\n const typeId = c.req.query(\"type\") ?? project.listTypes()[0]?.id;\n const enSlug = c.req.query(\"slug\");\n if (!typeId) return c.html(renderLayout(\"History\", \"<p>No content types.</p>\"));\n\n const db = openStore(config, \"readonly\");\n let body = `<h1>History</h1><form><label>Type <select name=\"type\">${project\n .listTypes()\n .map((t) => `<option value=\"${t.id}\" ${t.id === typeId ? \"selected\" : \"\"}>${t.id}</option>`)\n .join(\"\")}</select></label> <label>EN slug <input name=\"slug\" value=\"${enSlug ?? \"\"}\" /></label> <button>View</button></form>`;\n\n if (enSlug) {\n const rows = listRevisions(db, typeId, enSlug)\n .slice(0, 100)\n .map(\n (row) =>\n `<tr><td>${row.created_at}</td><td>${row.revision_kind}</td><td>${row.locale ?? \"en\"}</td><td>${row.en_hash.slice(0, 8)}</td><td class=\"muted\">${row.body_preview ?? \"\"}</td></tr>`,\n )\n .join(\"\");\n body += `<table><thead><tr><th>When</th><th>Kind</th><th>Locale</th><th>EN hash</th><th>Preview</th></tr></thead><tbody>${rows}</tbody></table>`;\n } else {\n const translations = listTranslationsForType(db, typeId).slice(0, 100);\n body += `<ul>${translations\n .map((row) => `<li><a href=\"/history?type=${typeId}&slug=${row.en_slug}\">${row.en_slug}</a> (${row.locale})</li>`)\n .join(\"\")}</ul>`;\n }\n db.close();\n return c.html(renderLayout(\"History\", body));\n });\n\n app.get(\"/api/staleness-matrix\", (c) => {\n const matrix: Record<string, Record<string, number>> = {};\n for (const type of project.listTypes()) {\n matrix[type.id] = {};\n for (const locale of config.locales) {\n if (locale === config.defaultLocale) continue;\n const enSlugs = type.list().map((doc) => doc.slug);\n let stale = 0;\n for (const enSlug of enSlugs) {\n const enDoc = readEnDocument(config, type.config, enSlug);\n if (!enDoc) continue;\n const payload = getTranslatablePayload(enDoc, type.config);\n const hash = computePageEnHash(payload.frontmatter, payload.body);\n const db = openStore(config, \"readonly\");\n const row = db\n .prepare(\n `SELECT en_hash FROM translations WHERE content_type = ? AND en_slug = ? AND locale = ?`,\n )\n .get(type.id, enSlug, locale) as { en_hash: string } | undefined;\n db.close();\n if (!row || row.en_hash !== hash) stale++;\n }\n matrix[type.id]![locale] = stale;\n }\n }\n return c.json(matrix);\n });\n\n const port = options.port ?? 3600;\n const host = options.host ?? \"127.0.0.1\";\n serve({ fetch: app.fetch, port, hostname: host }, () => {\n console.log(`Scribe studio listening on http://${host}:${port}`);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/field.ts","../../src/core/introspect-schema.ts","../../src/hash/page-hash.ts","../../src/i18n/build-url.ts","../../src/core/builtin-fields.ts","../../src/storage/sqlite.ts","../../src/storage/translations.ts","../../src/loader/normalize-en.ts","../../src/loader/create-loader.ts","../../src/translate/worklist.ts","../../studio/server.ts"],"names":["path","createHash","z","fs","Database","matter","Hono","serve"],"mappings":"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","file":"server.cjs","sourcesContent":["import { z } from \"zod\";\nimport type { z as Zod } from \"zod\";\n\nconst FIELD_KIND = Symbol.for(\"@genlook/scribe/fieldKind\");\nconst RELATION_META = Symbol.for(\"@genlook/scribe/relationMeta\");\n\nexport type FieldKind = \"translatable\" | \"structural\";\n\nexport interface RelationMeta {\n typeId: string;\n multiple: boolean;\n optional: boolean;\n}\n\n/**\n * Type-level brand carried by `field.relation()` schemas so the target\n * content-type id (and multiplicity/optionality) survive into `related()`.\n * Never exists at runtime.\n */\nexport declare const RELATION_BRAND: unique symbol;\n\nexport interface RelationBrand<\n TTarget extends string = string,\n TMultiple extends boolean = boolean,\n TOptional extends boolean = boolean,\n> {\n target: TTarget;\n multiple: TMultiple;\n optional: TOptional;\n}\n\n/** A Zod schema branded with relation metadata (see `field.relation()`). */\nexport type RelationField<\n TZod extends Zod.ZodTypeAny,\n TBrand extends RelationBrand,\n> = TZod & { [RELATION_BRAND]: TBrand };\n\n/** Return whether a Zod field is translatable or structural. */\nexport function getFieldKind(schema: Zod.ZodTypeAny): FieldKind {\n const tagged = schema as Zod.ZodTypeAny & { [FIELD_KIND]?: FieldKind };\n return tagged[FIELD_KIND] ?? \"structural\";\n}\n\n/** Return relation metadata if the field was created with `field.relation()`. */\nexport function getRelationTarget(schema: Zod.ZodTypeAny): RelationMeta | null {\n let current: Zod.ZodTypeAny = schema;\n for (let i = 0; i < 8; i++) {\n const tagged = current as Zod.ZodTypeAny & {\n [RELATION_META]?: RelationMeta;\n unwrap?: () => Zod.ZodTypeAny;\n removeDefault?: () => Zod.ZodTypeAny;\n _def?: { innerType?: Zod.ZodTypeAny };\n };\n if (tagged[RELATION_META]) {\n return tagged[RELATION_META];\n }\n if (typeof tagged.unwrap === \"function\") {\n current = tagged.unwrap();\n continue;\n }\n if (typeof tagged.removeDefault === \"function\") {\n current = tagged.removeDefault();\n continue;\n }\n if (tagged._def?.innerType) {\n current = tagged._def.innerType;\n continue;\n }\n break;\n }\n return null;\n}\n\nfunction mark<T extends Zod.ZodTypeAny>(schema: T, kind: FieldKind): T {\n Object.defineProperty(schema, FIELD_KIND, {\n value: kind,\n enumerable: false,\n configurable: true,\n });\n return schema;\n}\n\nfunction markRelation<T extends Zod.ZodTypeAny>(schema: T, meta: RelationMeta): T {\n Object.defineProperty(schema, RELATION_META, {\n value: meta,\n enumerable: false,\n configurable: true,\n });\n return mark(schema, \"structural\");\n}\n\n/**\n * Options for `field.relation()`. Constraints live here (not as chained Zod\n * methods) because chaining clones the schema and would drop the relation\n * metadata.\n */\nexport interface RelationFieldOptions {\n /** The field holds an array of slugs instead of a single slug. */\n multiple?: boolean;\n /** The field may be omitted; `related()` then returns `null` (single) or `[]` (multiple). */\n optional?: boolean;\n /** Minimum item count (`multiple: true` only). */\n min?: number;\n /** Maximum item count (`multiple: true` only). */\n max?: number;\n}\n\ntype Bool<T> = [T] extends [true] ? true : false;\n\ntype RelationZod<TOpts extends RelationFieldOptions> =\n Bool<TOpts[\"optional\"]> extends true\n ? Zod.ZodOptional<\n Bool<TOpts[\"multiple\"]> extends true ? Zod.ZodArray<Zod.ZodString> : Zod.ZodString\n >\n : Bool<TOpts[\"multiple\"]> extends true\n ? Zod.ZodArray<Zod.ZodString>\n : Zod.ZodString;\n\ntype RelationFieldFor<\n TTarget extends string,\n TOpts extends RelationFieldOptions,\n> = RelationField<\n RelationZod<TOpts>,\n RelationBrand<TTarget, Bool<TOpts[\"multiple\"]>, Bool<TOpts[\"optional\"]>>\n>;\n\n/**\n * Mark Zod fields for Scribe:\n * - `translatable(schema)` — sent to the translator per locale.\n * - `structural(schema)` — EN-only; merged from EN into every locale document.\n * - `relation(typeId, options?)` — EN slug reference(s) to another content type,\n * validated by `scribe validate` and dereferenced via `scribe.<type>.related()`.\n */\nexport const field = {\n translatable: <T extends Zod.ZodTypeAny>(schema: T): T => mark(schema, \"translatable\"),\n structural: <T extends Zod.ZodTypeAny>(schema: T): T => mark(schema, \"structural\"),\n relation: <const TTarget extends string, const TOpts extends RelationFieldOptions = {}>(\n typeId: TTarget,\n options?: TOpts,\n ): RelationFieldFor<TTarget, TOpts> => {\n const multiple = options?.multiple ?? false;\n const optional = options?.optional ?? false;\n if ((options?.min !== undefined || options?.max !== undefined) && !multiple) {\n throw new Error(\n `field.relation(\"${typeId}\"): min/max require { multiple: true }`,\n );\n }\n let inner: Zod.ZodTypeAny;\n if (multiple) {\n let arr = z.array(z.string().min(1));\n if (options?.min !== undefined) arr = arr.min(options.min);\n if (options?.max !== undefined) arr = arr.max(options.max);\n inner = arr;\n } else {\n inner = z.string().min(1);\n }\n markRelation(inner, { typeId, multiple, optional });\n const schema = optional ? inner.optional() : inner;\n return schema as RelationFieldFor<TTarget, TOpts>;\n },\n};\n\n/** Strip Zod wrappers (optional, default, etc.) to reach the inner schema. */\nexport function unwrapSchema(schema: Zod.ZodTypeAny): Zod.ZodTypeAny {\n let current: Zod.ZodTypeAny = schema;\n for (let i = 0; i < 8; i++) {\n const anySchema = current as Zod.ZodTypeAny & {\n unwrap?: () => Zod.ZodTypeAny;\n removeDefault?: () => Zod.ZodTypeAny;\n _def?: { innerType?: Zod.ZodTypeAny; type?: string };\n };\n if (typeof anySchema.unwrap === \"function\") {\n current = anySchema.unwrap();\n continue;\n }\n if (typeof anySchema.removeDefault === \"function\") {\n current = anySchema.removeDefault();\n continue;\n }\n if (anySchema._def?.innerType) {\n current = anySchema._def.innerType;\n continue;\n }\n break;\n }\n return current;\n}\n\n/** Strip optional/default/nullable wrappers only — preserves arrays and objects. */\nexport function peelOptionalWrappers(schema: Zod.ZodTypeAny): Zod.ZodTypeAny {\n let current: Zod.ZodTypeAny = schema;\n for (let i = 0; i < 8; i++) {\n const type = (current as Zod.ZodTypeAny & { _def?: { type?: string } })._def?.type;\n if (type === \"optional\" || type === \"nullable\") {\n current = (current as Zod.ZodOptional<Zod.ZodTypeAny>).unwrap();\n continue;\n }\n if (type === \"default\") {\n current = (current as Zod.ZodDefault<Zod.ZodTypeAny>).removeDefault();\n continue;\n }\n break;\n }\n return current;\n}\n","import type { z } from \"zod\";\nimport { getFieldKind, getRelationTarget, unwrapSchema } from \"./field.js\";\n\nexport interface SchemaFieldMeta {\n path: string[];\n kind: \"translatable\" | \"structural\" | \"relation\";\n relationTarget?: string;\n relationMultiple?: boolean;\n relationOptional?: boolean;\n}\n\n/** List schema fields with translatable/structural/relation metadata. */\nexport function introspectSchema(schema: z.ZodTypeAny, prefix: string[] = []): SchemaFieldMeta[] {\n const relation = getRelationTarget(schema);\n if (relation && prefix.length > 0) {\n return [\n {\n path: prefix,\n kind: \"relation\",\n relationTarget: relation.typeId,\n relationMultiple: relation.multiple,\n relationOptional: relation.optional,\n },\n ];\n }\n\n const base = unwrapSchema(schema);\n if (base instanceof Object && \"shape\" in base) {\n const shape = (base as z.ZodObject<z.ZodRawShape>).shape;\n const fields: SchemaFieldMeta[] = [];\n for (const [key, child] of Object.entries(shape)) {\n fields.push(...introspectSchema(child as z.ZodTypeAny, [...prefix, key]));\n }\n return fields;\n }\n\n if (base instanceof Object && \"element\" in base) {\n const element = (base as z.ZodArray<z.ZodTypeAny>).element;\n const elementBase = unwrapSchema(element);\n if (elementBase instanceof Object && \"shape\" in elementBase) {\n const shape = (elementBase as z.ZodObject<z.ZodRawShape>).shape;\n const fields: SchemaFieldMeta[] = [];\n for (const [key, child] of Object.entries(shape)) {\n fields.push(...introspectSchema(child as z.ZodTypeAny, [...prefix, \"*\", key]));\n }\n return fields;\n }\n }\n\n return [{ path: prefix, kind: getFieldKind(schema) }];\n}\n\nexport function extractByPaths(\n data: Record<string, unknown>,\n paths: string[][],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const path of paths) {\n const value = getAtPath(data, path);\n if (value !== undefined) {\n setAtPath(out, path.filter((p) => p !== \"*\"), value);\n }\n }\n return out;\n}\n\n/** Extract frontmatter fields marked as translatable. */\nexport function pickTranslatable(data: Record<string, unknown>, schema: z.ZodTypeAny): Record<string, unknown> {\n const translatablePaths = introspectSchema(schema)\n .filter((f) => f.kind === \"translatable\")\n .map((f) => f.path);\n return extractByPaths(data, translatablePaths);\n}\n\n/** Extract frontmatter fields marked as structural (EN-only). */\nexport function pickStructural(data: Record<string, unknown>, schema: z.ZodTypeAny): Record<string, unknown> {\n const structuralPaths = introspectSchema(schema)\n .filter((f) => f.kind === \"structural\" || f.kind === \"relation\")\n .map((f) => f.path);\n return extractByPaths(data, structuralPaths);\n}\n\n/** Merge EN structural fields onto a locale document's frontmatter at load time. */\nexport function mergeStructuralOntoLocale(\n localeData: Record<string, unknown>,\n enData: Record<string, unknown>,\n schema: z.ZodTypeAny,\n): Record<string, unknown> {\n const structural = pickStructural(enData, schema);\n const translatable = pickTranslatable(localeData, schema);\n return deepMerge(structural, translatable);\n}\n\nfunction getAtPath(obj: Record<string, unknown>, path: string[]): unknown {\n let current: unknown = obj;\n for (const segment of path) {\n if (segment === \"*\") {\n if (!Array.isArray(current)) return undefined;\n return current.map((item) =>\n typeof item === \"object\" && item !== null\n ? getAtPath(item as Record<string, unknown>, path.slice(path.indexOf(\"*\") + 1))\n : undefined,\n );\n }\n if (typeof current !== \"object\" || current === null || Array.isArray(current)) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\nfunction setAtPath(obj: Record<string, unknown>, path: string[], value: unknown): void {\n if (path.length === 0) return;\n if (path.length === 1) {\n obj[path[0]!] = value;\n return;\n }\n const [head, ...rest] = path;\n if (!(head! in obj) || typeof obj[head!] !== \"object\" || obj[head!] === null) {\n obj[head!] = {};\n }\n setAtPath(obj[head!] as Record<string, unknown>, rest, value);\n}\n\nfunction deepMerge(base: Record<string, unknown>, overlay: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(overlay)) {\n if (\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n out[key] &&\n typeof out[key] === \"object\" &&\n !Array.isArray(out[key])\n ) {\n out[key] = deepMerge(out[key] as Record<string, unknown>, value as Record<string, unknown>);\n } else if (Array.isArray(value) && Array.isArray(out[key])) {\n out[key] = mergeArrayOverlay(out[key] as unknown[], value as unknown[]);\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n\nfunction mergeArrayOverlay(base: unknown[], overlay: unknown[]): unknown[] {\n return base.map((item, index) => {\n const overlayItem = overlay[index];\n if (\n item &&\n typeof item === \"object\" &&\n !Array.isArray(item) &&\n overlayItem &&\n typeof overlayItem === \"object\" &&\n !Array.isArray(overlayItem)\n ) {\n return deepMerge(item as Record<string, unknown>, overlayItem as Record<string, unknown>);\n }\n return overlayItem ?? item;\n });\n}\n\n/** Collect relation field paths and targets from a content schema. */\nexport function listRelationFields(schema: z.ZodTypeAny): SchemaFieldMeta[] {\n return introspectSchema(schema).filter((f) => f.kind === \"relation\");\n}\n","import { createHash } from \"node:crypto\";\n\n/** SHA-256 hex digest of a UTF-8 string. */\nexport function sha256(input: string): string {\n return createHash(\"sha256\").update(input, \"utf8\").digest(\"hex\");\n}\n\n/** Hash translatable frontmatter + body for translation staleness detection. */\nexport function computePageEnHash(\n translatableFrontmatter: Record<string, unknown>,\n body: string,\n): string {\n const payload = JSON.stringify({ frontmatter: translatableFrontmatter, body });\n return sha256(payload);\n}\n\n/** Hash MDX body content for revision tracking. */\nexport function computeBodyHash(body: string): string {\n return sha256(body);\n}\n","import type { ContentTypeConfig } from \"../core/types.js\";\n\nconst SLUG_PLACEHOLDER = \"{slug}\";\n\n/** Whether a content type has a public URL path template. */\nexport function isRoutableType(type: Pick<ContentTypeConfig, \"path\">): boolean {\n return typeof type.path === \"string\" && type.path.length > 0;\n}\n\n/** Validate path template at project init. */\nexport function assertValidPathTemplate(path: string, typeId: string): void {\n if (!path.startsWith(\"/\")) {\n throw new Error(`Content type \"${typeId}\": path must start with / (got \"${path}\")`);\n }\n const count = (path.match(/\\{slug\\}/g) ?? []).length;\n if (count !== 1) {\n throw new Error(\n `Content type \"${typeId}\": path must contain exactly one {slug} (got \"${path}\")`,\n );\n }\n}\n\n/** Segment before `{slug}` in the template, e.g. `/blog/` from `/blog/{slug}`. */\nexport function pathPrefix(template: string): string {\n const idx = template.indexOf(SLUG_PLACEHOLDER);\n if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);\n return template.slice(0, idx);\n}\n\n/** Segment after `{slug}` in the template, e.g. `/advanced` from `/blog/{slug}/advanced`. */\nexport function pathSuffix(template: string): string {\n const idx = template.indexOf(SLUG_PLACEHOLDER);\n if (idx === -1) throw new Error(`Invalid path template (missing {slug}): ${template}`);\n return template.slice(idx + SLUG_PLACEHOLDER.length);\n}\n\n/** Build a locale-aware pathname from a path template and slug. */\nexport function resolvePath(\n template: string,\n slug: string,\n locale: string,\n defaultLocale: string,\n): string {\n const relative = template.replace(SLUG_PLACEHOLDER, slug);\n if (locale === defaultLocale) return relative;\n return `/${locale}${relative}`;\n}\n\n/** Extract slug from a resolved path that matches the template. */\nexport function extractSlugFromResolvedPath(template: string, resolvedPath: string): string | null {\n const prefix = pathPrefix(template);\n const suffix = pathSuffix(template);\n if (!resolvedPath.startsWith(prefix)) return null;\n if (suffix && !resolvedPath.endsWith(suffix)) return null;\n const slugEnd = suffix ? resolvedPath.length - suffix.length : resolvedPath.length;\n const slug = resolvedPath.slice(prefix.length, slugEnd);\n return slug.length > 0 ? slug : null;\n}\n","import { z } from \"zod\";\nimport { extractSlugFromResolvedPath, pathPrefix, pathSuffix, resolvePath } from \"../i18n/build-url.js\";\nimport type { ContentTypeConfig, ScribeDocument } from \"./types.js\";\n\nexport const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport const slugPatternSchema = z\n .string()\n .regex(SLUG_PATTERN, \"slug must be lowercase-kebab-case\");\n\nexport const isoDateSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}(T[\\d:.Z+-]*)?$/, \"Use ISO date YYYY-MM-DD or full ISO 8601\");\n\nconst canonicalPathSchema = z.string().regex(/^\\//, \"canonicalPath must start with /\");\n\nexport interface BuiltinEnFields {\n aliases: string[];\n redirectTo?: string;\n publishedAt?: string;\n updatedAt?: string;\n noindex: boolean;\n /** Set only when explicitly provided in EN frontmatter. */\n canonicalPathOverride?: string;\n}\n\nexport interface BuiltinParseIssue {\n field: string;\n message: string;\n level: \"error\" | \"warning\";\n}\n\nconst LOCALE_BUILTIN_KEYS: Array<[string, string]> = [\n [\"publishedAt\", \"publishedAt is EN-only; inherited from the EN parent at load time\"],\n [\"updatedAt\", \"updatedAt is EN-only; inherited from the EN parent at load time\"],\n [\"noindex\", \"noindex is EN-only; inherited from the EN parent at load time\"],\n [\"canonicalPath\", \"canonicalPath is EN-only; inherited from the EN parent at load time\"],\n [\"aliases\", \"aliases is EN-only; remove from locale translation\"],\n [\"redirect_to\", \"redirect_to is EN-only; remove from locale translation\"],\n [\"translationOf\", \"translationOf is internal; remove from locale translation\"],\n [\"enSlug\", \"enSlug is internal; remove from locale translation\"],\n];\n\n/** Extract built-in EN frontmatter (aliases, dates, SEO) before Zod validation. */\nexport function extractBuiltinEnFields(\n data: Record<string, unknown>,\n pathTemplate: string | undefined,\n enSlug: string,\n defaultLocale: string,\n): {\n builtin: BuiltinEnFields;\n rest: Record<string, unknown>;\n issues: BuiltinParseIssue[];\n} {\n const issues: BuiltinParseIssue[] = [];\n const rest = { ...data };\n\n const aliasesResult = z.array(slugPatternSchema).max(20).optional().default([]).safeParse(rest.aliases ?? []);\n delete rest.aliases;\n\n const redirectRaw = rest.redirect_to;\n delete rest.redirect_to;\n\n let redirectTo: string | undefined;\n if (redirectRaw !== undefined && redirectRaw !== null && redirectRaw !== \"\") {\n if (typeof redirectRaw !== \"string\") {\n issues.push({\n field: \"redirect_to\",\n message: \"redirect_to must be a string path\",\n level: \"error\",\n });\n } else if (!pathTemplate) {\n issues.push({\n field: \"redirect_to\",\n message: \"redirect_to is not allowed on reference-only content types\",\n level: \"error\",\n });\n } else if (!extractSlugFromResolvedPath(pathTemplate, redirectRaw)) {\n issues.push({\n field: \"redirect_to\",\n message: `redirect_to must match path template \"${pathTemplate}\" (prefix \"${pathPrefix(pathTemplate)}\"${pathSuffix(pathTemplate) ? `, suffix \"${pathSuffix(pathTemplate)}\"` : \"\"})`,\n level: \"error\",\n });\n } else {\n redirectTo = redirectRaw;\n }\n }\n\n const aliases = aliasesResult.success ? aliasesResult.data : [];\n if (!aliasesResult.success) {\n for (const issue of aliasesResult.error.issues) {\n issues.push({\n field: `aliases.${issue.path.join(\".\")}`,\n message: issue.message,\n level: \"error\",\n });\n }\n }\n\n let publishedAt: string | undefined;\n if (rest.publishedAt !== undefined && rest.publishedAt !== null && rest.publishedAt !== \"\") {\n const parsed = isoDateSchema.safeParse(rest.publishedAt);\n if (parsed.success) {\n publishedAt = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"publishedAt\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.publishedAt;\n }\n\n let updatedAt: string | undefined;\n if (rest.updatedAt !== undefined && rest.updatedAt !== null && rest.updatedAt !== \"\") {\n const parsed = isoDateSchema.safeParse(rest.updatedAt);\n if (parsed.success) {\n updatedAt = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"updatedAt\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.updatedAt;\n } else if (publishedAt) {\n updatedAt = publishedAt;\n }\n\n let noindex = false;\n if (rest.noindex !== undefined && rest.noindex !== null && rest.noindex !== \"\") {\n if (typeof rest.noindex === \"boolean\") {\n noindex = rest.noindex;\n } else {\n issues.push({ field: \"noindex\", message: \"noindex must be a boolean\", level: \"error\" });\n }\n delete rest.noindex;\n }\n\n let canonicalPathOverride: string | undefined;\n if (rest.canonicalPath !== undefined && rest.canonicalPath !== null && rest.canonicalPath !== \"\") {\n const parsed = canonicalPathSchema.safeParse(rest.canonicalPath);\n if (parsed.success) {\n canonicalPathOverride = parsed.data;\n } else {\n for (const issue of parsed.error.issues) {\n issues.push({ field: \"canonicalPath\", message: issue.message, level: \"error\" });\n }\n }\n delete rest.canonicalPath;\n }\n\n for (const internalKey of [\"translationOf\", \"enSlug\"] as const) {\n if (rest[internalKey] !== undefined) {\n issues.push({\n field: internalKey,\n message: `${internalKey} is managed internally by Scribe; remove from frontmatter`,\n level: \"warning\",\n });\n delete rest[internalKey];\n }\n }\n\n return {\n builtin: {\n aliases,\n redirectTo,\n publishedAt,\n updatedAt,\n noindex,\n canonicalPathOverride,\n },\n rest,\n issues,\n };\n}\n\n/** Reject built-in keys on locale translation frontmatter. */\nexport function validateLocaleBuiltinFields(data: Record<string, unknown>): BuiltinParseIssue[] {\n const issues: BuiltinParseIssue[] = [];\n for (const [key, message] of LOCALE_BUILTIN_KEYS) {\n if (data[key] !== undefined) {\n issues.push({ field: key, message, level: \"error\" });\n }\n }\n return issues;\n}\n\n/** ISO date for sitemap lastmod from updatedAt or publishedAt. */\nexport function documentLastModified(doc: {\n updatedAt?: string;\n publishedAt?: string;\n}): string | undefined {\n const raw = doc.updatedAt ?? doc.publishedAt;\n if (!raw) return undefined;\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString();\n}\n\n/** Locale-aware pathname for a document. */\nexport function resolveCanonicalPathname(\n type: Pick<ContentTypeConfig, \"path\">,\n doc: Pick<ScribeDocument, \"slug\" | \"locale\" | \"canonicalPathOverride\">,\n defaultLocale: string,\n): string {\n if (doc.canonicalPathOverride) {\n if (doc.locale === defaultLocale) return doc.canonicalPathOverride;\n return `/${doc.locale}${doc.canonicalPathOverride}`;\n }\n if (!type.path) return `/${doc.slug}`;\n return resolvePath(type.path, doc.slug, doc.locale, defaultLocale);\n}\n\n/** Hydrate locale frontmatter with EN-only built-in fields at load time. */\nexport function mergeBuiltinsIntoFrontmatter(\n frontmatter: Record<string, unknown>,\n doc: Pick<\n ScribeDocument,\n \"publishedAt\" | \"updatedAt\" | \"noindex\" | \"canonicalPathOverride\" | \"slug\" | \"locale\"\n >,\n type: Pick<ContentTypeConfig, \"path\">,\n defaultLocale: string,\n): Record<string, unknown> {\n const out = { ...frontmatter };\n if (doc.publishedAt !== undefined) out.publishedAt = doc.publishedAt;\n if (doc.updatedAt !== undefined) out.updatedAt = doc.updatedAt;\n out.noindex = doc.noindex;\n out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale);\n return out;\n}\n\nexport function seoFieldsFromEn(enDoc: ScribeDocument): Pick<\n ScribeDocument,\n \"publishedAt\" | \"updatedAt\" | \"noindex\" | \"canonicalPathOverride\" | \"redirectTo\"\n> {\n return {\n publishedAt: enDoc.publishedAt,\n updatedAt: enDoc.updatedAt,\n noindex: enDoc.noindex,\n canonicalPathOverride: enDoc.canonicalPathOverride,\n redirectTo: enDoc.redirectTo,\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { ScribeConfig } from \"../core/types.js\";\n\nconst SCHEMA_VERSION = 3;\n\nconst MIGRATIONS: string[] = [\n `CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS translations (\n content_type TEXT NOT NULL,\n en_slug TEXT NOT NULL,\n locale TEXT NOT NULL,\n slug TEXT NOT NULL,\n frontmatter_json TEXT NOT NULL,\n body TEXT NOT NULL,\n en_hash TEXT NOT NULL,\n translated_at TEXT NOT NULL,\n model TEXT NOT NULL,\n PRIMARY KEY (content_type, en_slug, locale)\n )`,\n `CREATE INDEX IF NOT EXISTS idx_translations_type_locale\n ON translations(content_type, locale)`,\n `CREATE TABLE IF NOT EXISTS revisions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n content_type TEXT NOT NULL,\n en_slug TEXT NOT NULL,\n locale TEXT,\n revision_kind TEXT NOT NULL,\n en_hash TEXT NOT NULL,\n body_hash TEXT NOT NULL,\n created_at TEXT NOT NULL,\n model TEXT,\n body_preview TEXT\n )`,\n `CREATE INDEX IF NOT EXISTS idx_revisions_lookup\n ON revisions(content_type, en_slug, locale, created_at DESC)`,\n `CREATE TABLE IF NOT EXISTS slug_aliases (\n content_type TEXT NOT NULL,\n canonical_en_slug TEXT NOT NULL,\n alias_en_slug TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (content_type, alias_en_slug)\n )`,\n `CREATE INDEX IF NOT EXISTS idx_slug_aliases_canonical\n ON slug_aliases(content_type, canonical_en_slug)`,\n `CREATE TABLE IF NOT EXISTS alias_locale_slugs (\n content_type TEXT NOT NULL,\n alias_en_slug TEXT NOT NULL,\n locale TEXT NOT NULL,\n locale_slug TEXT NOT NULL,\n captured_at TEXT NOT NULL,\n PRIMARY KEY (content_type, alias_en_slug, locale)\n )`,\n];\n\nexport type SqliteMode = \"readonly\" | \"readwrite\";\n\n/** Absolute path to the SQLite translation store (precomputed by `resolveConfig`). */\nexport function resolveStorePath(config: ScribeConfig): string {\n return config.storePath;\n}\n\n/** Open the SQLite translation store (creates schema if missing). */\nexport function openStore(config: ScribeConfig, mode: SqliteMode = \"readwrite\"): Database.Database {\n const storePath = resolveStorePath(config);\n if (mode === \"readwrite\") {\n fs.mkdirSync(path.dirname(storePath), { recursive: true });\n }\n const db = new Database(storePath, { readonly: mode === \"readonly\" });\n if (mode === \"readwrite\") {\n migrate(db);\n }\n return db;\n}\n\nfunction addColumnIfMissing(\n db: Database.Database,\n table: string,\n column: string,\n ddlType: string,\n): void {\n const columns = db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>;\n if (!columns.some((c) => c.name === column)) {\n db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${ddlType}`);\n }\n}\n\nfunction migrate(db: Database.Database): void {\n for (const sql of MIGRATIONS) {\n db.exec(sql);\n }\n // v3: store a full content snapshot (translated frontmatter + body) on each\n // revision so history can show — and diff — past versions, not just a preview.\n addColumnIfMissing(db, \"revisions\", \"frontmatter_json\", \"TEXT\");\n addColumnIfMissing(db, \"revisions\", \"body\", \"TEXT\");\n db.prepare(\n `INSERT INTO meta(key, value) VALUES('schema_version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n ).run(String(SCHEMA_VERSION));\n}\n\nexport function closeStore(db: Database.Database): void {\n db.close();\n}\n","import type Database from \"better-sqlite3\";\n\nexport interface TranslationRow {\n content_type: string;\n en_slug: string;\n locale: string;\n slug: string;\n frontmatter_json: string;\n body: string;\n en_hash: string;\n translated_at: string;\n model: string;\n}\n\nexport interface TranslationInput {\n contentType: string;\n enSlug: string;\n locale: string;\n slug: string;\n frontmatter: Record<string, unknown>;\n body: string;\n enHash: string;\n translatedAt: string;\n model: string;\n}\n\nexport interface RevisionInput {\n contentType: string;\n enSlug: string;\n locale: string | null;\n revisionKind: \"translation\" | \"en_edit_detected\" | \"snapshot\";\n enHash: string;\n bodyHash: string;\n createdAt: string;\n model?: string;\n bodyPreview?: string;\n /** Full translated frontmatter snapshot (JSON) at revision time. */\n frontmatterJson?: string | null;\n /** Full translated body snapshot at revision time. */\n body?: string | null;\n}\n\nexport interface RevisionRow {\n id: number;\n content_type: string;\n en_slug: string;\n locale: string | null;\n revision_kind: string;\n en_hash: string;\n body_hash: string;\n created_at: string;\n model: string | null;\n body_preview: string | null;\n frontmatter_json: string | null;\n body: string | null;\n}\n\nexport function upsertTranslation(db: Database.Database, input: TranslationInput): void {\n db.prepare(\n `INSERT INTO translations (\n content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(content_type, en_slug, locale) DO UPDATE SET\n slug = excluded.slug,\n frontmatter_json = excluded.frontmatter_json,\n body = excluded.body,\n en_hash = excluded.en_hash,\n translated_at = excluded.translated_at,\n model = excluded.model`,\n ).run(\n input.contentType,\n input.enSlug,\n input.locale,\n input.slug,\n JSON.stringify(input.frontmatter),\n input.body,\n input.enHash,\n input.translatedAt,\n input.model,\n );\n}\n\nexport function getTranslation(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n locale: string,\n): TranslationRow | undefined {\n return db\n .prepare(\n `SELECT * FROM translations WHERE content_type = ? AND en_slug = ? AND locale = ?`,\n )\n .get(contentType, enSlug, locale) as TranslationRow | undefined;\n}\n\nexport function listTranslationsForType(\n db: Database.Database,\n contentType: string,\n): TranslationRow[] {\n return db\n .prepare(`SELECT * FROM translations WHERE content_type = ? ORDER BY en_slug, locale`)\n .all(contentType) as TranslationRow[];\n}\n\nexport function listTranslationsForEnSlug(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n): TranslationRow[] {\n return db\n .prepare(\n `SELECT * FROM translations WHERE content_type = ? AND en_slug = ? ORDER BY locale`,\n )\n .all(contentType, enSlug) as TranslationRow[];\n}\n\nexport function listTranslationsForLocale(\n db: Database.Database,\n contentType: string,\n locale: string,\n): TranslationRow[] {\n return db\n .prepare(`SELECT * FROM translations WHERE content_type = ? AND locale = ? ORDER BY en_slug`)\n .all(contentType, locale) as TranslationRow[];\n}\n\nexport function bulkLoadTranslations(db: Database.Database): TranslationRow[] {\n return db.prepare(`SELECT * FROM translations ORDER BY content_type, en_slug, locale`).all() as TranslationRow[];\n}\n\nexport function appendRevision(db: Database.Database, input: RevisionInput): number {\n const result = db\n .prepare(\n `INSERT INTO revisions (\n content_type, en_slug, locale, revision_kind, en_hash, body_hash, created_at,\n model, body_preview, frontmatter_json, body\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n input.contentType,\n input.enSlug,\n input.locale,\n input.revisionKind,\n input.enHash,\n input.bodyHash,\n input.createdAt,\n input.model ?? null,\n input.bodyPreview ?? null,\n input.frontmatterJson ?? null,\n input.body ?? null,\n );\n return Number(result.lastInsertRowid);\n}\n\n/** List revision history for an EN slug, optionally filtered by locale. */\nexport function listRevisions(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n locale?: string,\n): RevisionRow[] {\n if (locale) {\n return db\n .prepare(\n `SELECT * FROM revisions\n WHERE content_type = ? AND en_slug = ? AND locale = ?\n ORDER BY created_at DESC, id DESC`,\n )\n .all(contentType, enSlug, locale) as RevisionRow[];\n }\n return db\n .prepare(\n `SELECT * FROM revisions\n WHERE content_type = ? AND en_slug = ?\n ORDER BY created_at DESC, id DESC`,\n )\n .all(contentType, enSlug) as RevisionRow[];\n}\n\nexport function countTranslations(db: Database.Database): number {\n const row = db.prepare(`SELECT COUNT(*) as count FROM translations`).get() as { count: number };\n return row.count;\n}\n\nexport function countStaleTranslations(\n db: Database.Database,\n contentType: string,\n enSlug: string,\n currentEnHash: string,\n): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) as count FROM translations\n WHERE content_type = ? AND en_slug = ? AND en_hash != ?`,\n )\n .get(contentType, enSlug, currentEnHash) as { count: number };\n return row.count;\n}\n","export function normalizeEnFrontmatter(data: Record<string, unknown>): Record<string, unknown> {\n const out = { ...data };\n if (!out.publishedAt && typeof out.date === \"string\") {\n out.publishedAt = out.date;\n }\n if (!out.heroImage && typeof out.image === \"string\" && out.image.startsWith(\"/\")) {\n out.heroImage = out.image;\n }\n if (!out.updatedAt && typeof out.publishedAt === \"string\") {\n out.updatedAt = out.publishedAt;\n }\n return out;\n}\n\nexport function isPublishableContentFile(name: string): boolean {\n if (!name.endsWith(\".md\") && !name.endsWith(\".mdx\")) return false;\n const first = name.charAt(0);\n return first === first.toLowerCase() && first !== \"_\";\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport matter from \"gray-matter\";\nimport type { z } from \"zod\";\nimport {\n extractBuiltinEnFields,\n mergeBuiltinsIntoFrontmatter,\n seoFieldsFromEn,\n} from \"../core/builtin-fields.js\";\nimport { mergeStructuralOntoLocale, pickTranslatable } from \"../core/introspect-schema.js\";\nimport type {\n AllDocuments,\n ContentTypeConfig,\n LocaleIndex,\n ScribeConfig,\n ScribeDocument,\n} from \"../core/types.js\";\nimport { openStore, resolveStorePath } from \"../storage/sqlite.js\";\nimport { listTranslationsForType } from \"../storage/translations.js\";\nimport { isPublishableContentFile, normalizeEnFrontmatter } from \"./normalize-en.js\";\n\nfunction isPostFile(name: string): boolean {\n return isPublishableContentFile(name);\n}\n\nfunction listEnFiles(contentDir: string): string[] {\n if (!fs.existsSync(contentDir)) return [];\n return fs\n .readdirSync(contentDir)\n .filter(isPostFile)\n .map((f) => path.join(contentDir, f));\n}\n\nfunction slugFromPath(filePath: string): string {\n return path.basename(filePath).replace(/\\.(md|mdx)$/, \"\");\n}\n\nexport interface ParseEnResult {\n document: ScribeDocument | null;\n issues: Array<{ field: string; message: string; level: \"error\" | \"warning\" }>;\n}\n\nexport function parseEnMdx(\n filePath: string,\n config: ScribeConfig,\n type: ContentTypeConfig,\n): ParseEnResult {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = matter(raw);\n const slug = slugFromPath(filePath);\n const normalized = normalizeEnFrontmatter(parsed.data as Record<string, unknown>);\n const { builtin, rest, issues: builtinIssues } = extractBuiltinEnFields(\n normalized,\n type.path,\n slug,\n config.defaultLocale,\n );\n const issues = builtinIssues.map((issue) => ({\n field: issue.field,\n message: issue.message,\n level: issue.level,\n }));\n\n const result = type.schema.safeParse(rest);\n if (!result.success) {\n return {\n document: null,\n issues: [\n ...issues,\n ...result.error.issues.map((issue) => ({\n field: issue.path.join(\".\"),\n message: issue.message,\n level: \"error\" as const,\n })),\n ],\n };\n }\n\n if (issues.some((i) => i.level === \"error\")) {\n return { document: null, issues };\n }\n\n const frontmatter = mergeBuiltinsIntoFrontmatter(\n result.data as Record<string, unknown>,\n {\n publishedAt: builtin.publishedAt,\n updatedAt: builtin.updatedAt,\n noindex: builtin.noindex,\n canonicalPathOverride: builtin.canonicalPathOverride,\n slug,\n locale: config.defaultLocale,\n },\n type,\n config.defaultLocale,\n );\n\n const crossIssues = type.crossValidate?.(result.data as z.infer<typeof type.schema>, {\n locale: config.defaultLocale,\n defaultLocale: config.defaultLocale,\n slug,\n enSlug: slug,\n knownLocales: config.locales,\n }) ?? [];\n issues.push(...crossIssues);\n\n const document: ScribeDocument = {\n slug,\n enSlug: slug,\n locale: config.defaultLocale,\n aliases: builtin.aliases,\n redirectTo: builtin.redirectTo,\n publishedAt: builtin.publishedAt,\n updatedAt: builtin.updatedAt,\n noindex: builtin.noindex,\n canonicalPathOverride: builtin.canonicalPathOverride,\n frontmatter,\n content: parsed.content,\n filePath,\n };\n\n return { document, issues };\n}\n\nfunction buildDocumentFromTranslation(\n row: {\n slug: string;\n en_slug: string;\n locale: string;\n frontmatter_json: string;\n body: string;\n },\n enDoc: ScribeDocument,\n type: ContentTypeConfig,\n): ScribeDocument {\n const localeFm = JSON.parse(row.frontmatter_json) as Record<string, unknown>;\n const merged = mergeStructuralOntoLocale(localeFm, enDoc.frontmatter, type.schema);\n const seo = seoFieldsFromEn(enDoc);\n const frontmatter = mergeBuiltinsIntoFrontmatter(\n merged,\n { ...seo, slug: row.slug, locale: row.locale },\n type,\n enDoc.locale,\n );\n\n return {\n slug: row.slug,\n enSlug: row.en_slug,\n locale: row.locale,\n aliases: [],\n redirectTo: seo.redirectTo,\n publishedAt: seo.publishedAt,\n updatedAt: seo.updatedAt,\n noindex: seo.noindex,\n canonicalPathOverride: seo.canonicalPathOverride,\n frontmatter,\n content: row.body,\n };\n}\n\nconst DEV_REVALIDATE_MS = 1500;\n\nexport function createContentLoader(config: ScribeConfig, type: ContentTypeConfig): () => AllDocuments {\n let cached: AllDocuments | null = null;\n let signature = \"\";\n let lastCheck = 0;\n const contentDir = path.join(/* turbopackIgnore: true */ config.rootDir, type.contentDir);\n const storePath = resolveStorePath(config);\n const isProd = process.env.NODE_ENV === \"production\";\n\n function computeSignature(): string {\n const files = listEnFiles(contentDir);\n let newest = 0;\n for (const f of files) {\n try {\n newest = Math.max(newest, fs.statSync(f).mtimeMs);\n } catch {\n /* ignore */\n }\n }\n let store = 0;\n try {\n store = fs.statSync(storePath).mtimeMs;\n } catch {\n /* ignore */\n }\n return `${files.length}:${newest}:${store}`;\n }\n\n function build(): AllDocuments {\n const out = new Map<string, LocaleIndex>();\n const englishBySlug = new Map<string, ScribeDocument>();\n\n for (const file of listEnFiles(contentDir)) {\n const { document, issues } = parseEnMdx(file, config, type);\n if (document) {\n englishBySlug.set(document.slug, document);\n if (issues.length > 0) {\n for (const issue of issues) {\n console.warn(\n `[scribe:${type.id}] ${file} ${issue.level}: ${issue.field}: ${issue.message}`,\n );\n }\n }\n } else {\n console.warn(\n `[scribe:${type.id}] Skipping ${file} — validation failed:\\n` +\n issues.map((i) => ` - ${i.field}: ${i.message}`).join(\"\\n\"),\n );\n }\n }\n\n out.set(config.defaultLocale, {\n bySlug: englishBySlug,\n byEnSlug: englishBySlug,\n });\n\n const db = openStore(config, \"readonly\");\n const rows = listTranslationsForType(db, type.id);\n db.close();\n\n const rowsByLocale = new Map<string, typeof rows>();\n for (const row of rows) {\n const list = rowsByLocale.get(row.locale) ?? [];\n list.push(row);\n rowsByLocale.set(row.locale, list);\n }\n\n for (const locale of config.locales) {\n if (locale === config.defaultLocale) continue;\n const bySlug = new Map<string, ScribeDocument>();\n const byEnSlug = new Map<string, ScribeDocument>();\n for (const row of rowsByLocale.get(locale) ?? []) {\n const enDoc = englishBySlug.get(row.en_slug);\n if (!enDoc) continue;\n const doc = buildDocumentFromTranslation(row, enDoc, type);\n bySlug.set(doc.slug, doc);\n byEnSlug.set(row.en_slug, doc);\n }\n out.set(locale, { bySlug, byEnSlug });\n }\n\n return out;\n }\n\n return () => {\n if (cached) {\n if (isProd) return cached;\n const now = Date.now();\n if (now - lastCheck < DEV_REVALIDATE_MS) return cached;\n lastCheck = now;\n const sig = computeSignature();\n if (sig === signature) return cached;\n cached = build();\n signature = sig;\n return cached;\n }\n lastCheck = Date.now();\n cached = build();\n signature = isProd ? \"\" : computeSignature();\n return cached;\n };\n}\n\nexport function readEnDocument(\n config: ScribeConfig,\n type: ContentTypeConfig,\n enSlug: string,\n): ScribeDocument | null {\n const contentDir = path.join(/* turbopackIgnore: true */ config.rootDir, type.contentDir);\n for (const ext of [\".mdx\", \".md\"]) {\n const filePath = path.join(contentDir, `${enSlug}${ext}`);\n if (!fs.existsSync(filePath)) continue;\n const { document } = parseEnMdx(filePath, config, type);\n return document;\n }\n return null;\n}\n\nexport function getTranslatablePayload(\n doc: ScribeDocument,\n type: ContentTypeConfig,\n): { frontmatter: Record<string, unknown>; body: string } {\n return {\n frontmatter: pickTranslatable(doc.frontmatter, type.schema),\n body: doc.content,\n };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ScribeConfig } from \"../core/types.js\";\nimport { isPublishableContentFile } from \"../loader/normalize-en.js\";\nimport { computePageEnHash } from \"../hash/page-hash.js\";\nimport { getTranslatablePayload, readEnDocument } from \"../loader/create-loader.js\";\nimport { openStore } from \"../storage/sqlite.js\";\nimport { getTranslation } from \"../storage/translations.js\";\n\nexport interface TranslationWorkItem {\n contentType: string;\n enSlug: string;\n locale: string;\n reason: \"missing\" | \"stale\";\n currentEnHash: string;\n storedEnHash?: string;\n}\n\nexport type TranslationWorklistStrategy = \"all\" | \"missing-only\";\n\nexport interface WorklistOptions {\n contentType?: string;\n locales?: string[];\n enSlug?: string;\n /** Which pages to include: all stale/missing (default) or missing only. */\n strategy?: TranslationWorklistStrategy;\n}\n\nfunction listEnSlugs(rootDir: string, contentDir: string): string[] {\n const dir = path.join(rootDir, contentDir);\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter(isPublishableContentFile)\n .map((f) => f.replace(/\\.(md|mdx)$/, \"\"));\n}\n\n/** List locale pages that are missing or stale vs current EN content. */\nexport function buildWorklist(config: ScribeConfig, options: WorklistOptions = {}): TranslationWorkItem[] {\n const db = openStore(config, \"readonly\");\n const items: TranslationWorkItem[] = [];\n const locales =\n options.locales ??\n config.locales.filter((locale) => locale !== config.defaultLocale);\n\n for (const type of config.types) {\n if (options.contentType && type.id !== options.contentType) continue;\n const enSlugs = options.enSlug ? [options.enSlug] : listEnSlugs(config.rootDir, type.contentDir);\n\n for (const enSlug of enSlugs) {\n const enDoc = readEnDocument(config, type, enSlug);\n if (!enDoc) continue;\n const payload = getTranslatablePayload(enDoc, type);\n const currentEnHash = computePageEnHash(payload.frontmatter, payload.body);\n\n for (const locale of locales) {\n if (locale === config.defaultLocale) continue;\n const existing = getTranslation(db, type.id, enSlug, locale);\n if (!existing) {\n items.push({\n contentType: type.id,\n enSlug,\n locale,\n reason: \"missing\",\n currentEnHash,\n });\n continue;\n }\n if (existing.en_hash !== currentEnHash) {\n items.push({\n contentType: type.id,\n enSlug,\n locale,\n reason: \"stale\",\n currentEnHash,\n storedEnHash: existing.en_hash,\n });\n }\n }\n }\n }\n\n db.close();\n const strategy = options.strategy ?? \"all\";\n if (strategy === \"missing-only\") {\n return items.filter((item) => item.reason === \"missing\");\n }\n return items;\n}\n\n/** Resolve target locales from CLI flags or a named preset. */\nexport function resolveLocalesFromPreset(\n config: ScribeConfig,\n preset?: string,\n explicitLocales?: string[],\n): string[] {\n if (explicitLocales?.length) return explicitLocales;\n if (preset && config.localePresets?.[preset]) {\n return config.localePresets[preset]!.filter((l) => l !== config.defaultLocale);\n }\n return config.locales.filter((l) => l !== config.defaultLocale);\n}\n","import { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport type { ContentTypeRuntime, ScribeConfig, ScribeProject } from \"../src/core/types.js\";\nimport { introspectSchema, mergeStructuralOntoLocale } from \"../src/core/introspect-schema.js\";\nimport { computePageEnHash } from \"../src/hash/page-hash.js\";\nimport { getTranslatablePayload, readEnDocument } from \"../src/loader/create-loader.js\";\nimport { openStore } from \"../src/storage/sqlite.js\";\nimport {\n getTranslation,\n listRevisions,\n listTranslationsForLocale,\n type RevisionRow,\n} from \"../src/storage/translations.js\";\nimport { buildWorklist } from \"../src/translate/worklist.js\";\n\ntype DocStatus = \"source\" | \"up-to-date\" | \"stale\" | \"missing\";\n\ninterface DocumentStatusResult {\n status: DocStatus;\n currentEnHash?: string;\n storedEnHash?: string;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction encodePathSegment(value: string): string {\n return encodeURIComponent(value);\n}\n\nfunction statusDot(status: DocStatus): string {\n const labels: Record<DocStatus, string> = {\n source: \"en\",\n \"up-to-date\": \"ok\",\n stale: \"stale\",\n missing: \"—\",\n };\n return `<span class=\"status\" title=\"${status}\"><span class=\"dot dot-${status}\"></span>${labels[status]}</span>`;\n}\n\nfunction documentStatus(\n config: ScribeConfig,\n db: ReturnType<typeof openStore>,\n type: ContentTypeRuntime,\n enSlug: string,\n locale: string,\n): DocumentStatusResult {\n if (locale === config.defaultLocale) {\n return { status: \"source\" };\n }\n const enDoc = readEnDocument(config, type.config, enSlug);\n if (!enDoc) {\n return { status: \"missing\" };\n }\n const payload = getTranslatablePayload(enDoc, type.config);\n const currentEnHash = computePageEnHash(payload.frontmatter, payload.body);\n const row = getTranslation(db, type.id, enSlug, locale);\n if (!row) {\n return { status: \"missing\", currentEnHash };\n }\n if (row.en_hash !== currentEnHash) {\n return { status: \"stale\", currentEnHash, storedEnHash: row.en_hash };\n }\n return { status: \"up-to-date\", currentEnHash, storedEnHash: row.en_hash };\n}\n\nfunction flattenFrontmatter(\n data: Record<string, unknown>,\n prefix = \"\",\n): Array<{ key: string; value: string }> {\n const rows: Array<{ key: string; value: string }> = [];\n for (const [key, value] of Object.entries(data)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n rows.push(...flattenFrontmatter(value as Record<string, unknown>, fullKey));\n } else {\n const display =\n typeof value === \"string\"\n ? value\n : value === undefined\n ? \"\"\n : JSON.stringify(value, null, 2);\n rows.push({ key: fullKey, value: display });\n }\n }\n return rows;\n}\n\nfunction translatableKeySet(schema: ContentTypeRuntime[\"config\"][\"schema\"]): Set<string> {\n return new Set(\n introspectSchema(schema)\n .filter((field) => field.kind === \"translatable\")\n .map((field) => field.path.join(\".\")),\n );\n}\n\nfunction renderFrontmatterTable(\n frontmatter: Record<string, unknown>,\n schema: ContentTypeRuntime[\"config\"][\"schema\"],\n): string {\n const translatable = translatableKeySet(schema);\n const rows = flattenFrontmatter(frontmatter)\n .map((row) => {\n const flag = translatable.has(row.key)\n ? `<span class=\"flag t\" title=\"Translatable\">T</span>`\n : `<span class=\"flag s\" title=\"Structural\">S</span>`;\n return `<tr>\n <td class=\"k\">${flag}${escapeHtml(row.key)}</td>\n <td class=\"v\">${escapeHtml(row.value)}</td>\n </tr>`;\n })\n .join(\"\");\n return `<table class=\"kv\">\n <tbody>${rows || `<tr><td colspan=\"2\" class=\"dim\">—</td></tr>`}</tbody>\n </table>`;\n}\n\nfunction renderRevisionSnapshot(revision: RevisionRow): string {\n if (revision.frontmatter_json && revision.body) {\n let frontmatter: Record<string, unknown> = {};\n try {\n frontmatter = JSON.parse(revision.frontmatter_json) as Record<string, unknown>;\n } catch {\n frontmatter = {};\n }\n const fmRows = flattenFrontmatter(frontmatter)\n .map(\n (row) =>\n `<tr><td class=\"k\">${escapeHtml(row.key)}</td><td class=\"v\">${escapeHtml(row.value)}</td></tr>`,\n )\n .join(\"\");\n return `<table class=\"kv\"><tbody>${fmRows}</tbody></table>\n <pre class=\"code\">${escapeHtml(revision.body)}</pre>`;\n }\n return `<p class=\"dim\">${escapeHtml(revision.body_preview ?? \"(no snapshot)\")}</p>`;\n}\n\nfunction renderRevisionTimeline(revisions: RevisionRow[]): string {\n if (revisions.length === 0) {\n return `<p class=\"dim\">No history.</p>`;\n }\n const items = revisions\n .map(\n (row) => `<tr>\n <td class=\"dim\">${escapeHtml(row.created_at.slice(0, 19))}</td>\n <td>${escapeHtml(row.revision_kind)}</td>\n <td class=\"dim\">${row.model ? escapeHtml(row.model) : \"—\"}</td>\n <td class=\"dim mono\">${escapeHtml(row.en_hash.slice(0, 8))}</td>\n <td><details><summary>view</summary>${renderRevisionSnapshot(row)}</details></td>\n </tr>`,\n )\n .join(\"\");\n return `<table class=\"data\"><thead><tr>\n <th>When</th><th>Kind</th><th>Model</th><th>Hash</th><th></th>\n </tr></thead><tbody>${items}</tbody></table>`;\n}\n\nfunction renderLayout(\n title: string,\n body: string,\n project: ScribeProject,\n options: { activeTypeId?: string } = {},\n): string {\n const typeLinks = project\n .listTypes()\n .map((type) => {\n const active = type.id === options.activeTypeId ? \" active\" : \"\";\n return `<a class=\"tree-item${active}\" href=\"/type/${encodePathSegment(type.id)}\">\n <span class=\"tree-label\">${escapeHtml(type.config.label)}</span>\n <span class=\"tree-meta\">${escapeHtml(type.id)}</span>\n </a>`;\n })\n .join(\"\");\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${escapeHtml(title)} — Scribe</title>\n <style>\n :root {\n --bg: #1e1e1e;\n --sidebar: #252526;\n --bar: #333333;\n --panel: #1e1e1e;\n --border: #3c3c3c;\n --text: #cccccc;\n --dim: #858585;\n --accent: #3794ff;\n --hover: #2a2d2e;\n --active: #37373d;\n --ok: #89d185;\n --stale: #cca700;\n --missing: #f48771;\n --source: #75beff;\n --mono: ui-monospace, \"Cascadia Code\", \"SF Mono\", Menlo, monospace;\n --ui: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n --fs: 13px;\n --fs-sm: 11px;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font: var(--fs)/1.4 var(--ui); background: var(--bg); color: var(--text); }\n a { color: var(--accent); text-decoration: none; }\n a:hover { text-decoration: underline; }\n .app { display: flex; height: 100vh; overflow: hidden; }\n\n /* activity bar */\n .actbar {\n width: 48px; flex-shrink: 0; background: var(--bar);\n display: flex; flex-direction: column; align-items: center;\n padding: 8px 0; gap: 4px; border-right: 1px solid var(--border);\n }\n .actbar a {\n width: 48px; height: 48px; display: flex; align-items: center; justify-content: center;\n color: var(--dim); font-size: 18px; text-decoration: none; position: relative;\n }\n .actbar a:hover { color: var(--text); }\n .actbar a.active { color: var(--text); }\n .actbar a.active::before {\n content: \"\"; position: absolute; left: 0; top: 8px; bottom: 8px;\n width: 2px; background: var(--accent);\n }\n\n /* sidebar */\n .sidebar {\n width: 200px; flex-shrink: 0; background: var(--sidebar);\n border-right: 1px solid var(--border); display: flex; flex-direction: column;\n overflow: hidden;\n }\n .sidebar-head {\n padding: 8px 12px; font-size: var(--fs-sm); font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.04em; color: var(--dim);\n }\n .sidebar-body { flex: 1; overflow-y: auto; padding: 2px 0; }\n .tree-item {\n display: flex; flex-direction: column; padding: 3px 12px 3px 20px;\n color: var(--text); text-decoration: none; line-height: 1.3;\n }\n .tree-item:hover { background: var(--hover); text-decoration: none; }\n .tree-item.active { background: var(--active); }\n .tree-label { font-size: var(--fs); }\n .tree-meta { font-size: var(--fs-sm); color: var(--dim); }\n\n /* main */\n .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }\n .toolbar {\n display: flex; align-items: center; gap: 6px; padding: 0 12px;\n height: 35px; background: var(--sidebar); border-bottom: 1px solid var(--border);\n font-size: var(--fs-sm); color: var(--dim); flex-shrink: 0; overflow: hidden;\n }\n .toolbar a { color: var(--dim); }\n .toolbar a:hover { color: var(--text); }\n .toolbar .sep { color: var(--border); }\n .content { flex: 1; overflow-y: auto; padding: 0; }\n\n /* tabs (locale switcher) */\n .tabs {\n display: flex; background: var(--sidebar); border-bottom: 1px solid var(--border);\n overflow-x: auto; flex-shrink: 0;\n }\n .tab {\n display: flex; align-items: center; gap: 6px; padding: 6px 12px;\n font-size: var(--fs-sm); color: var(--dim); border-right: 1px solid var(--border);\n text-decoration: none; white-space: nowrap;\n }\n .tab:hover { background: var(--hover); color: var(--text); text-decoration: none; }\n .tab.active {\n background: var(--bg); color: var(--text);\n border-bottom: 1px solid var(--bg); margin-bottom: -1px;\n }\n\n /* status dots */\n .status { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-sm); color: var(--dim); }\n .dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }\n .dot-source { background: var(--source); }\n .dot-up-to-date { background: var(--ok); }\n .dot-stale { background: var(--stale); }\n .dot-missing { background: var(--missing); opacity: 0.7; }\n\n /* sections */\n .section { border-bottom: 1px solid var(--border); }\n .section-head {\n padding: 4px 12px; font-size: var(--fs-sm); font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.04em; color: var(--dim);\n background: var(--sidebar);\n }\n .section-body { padding: 0; }\n\n /* tables */\n table { border-collapse: collapse; width: 100%; font-size: var(--fs); }\n .data th, .data td { padding: 2px 12px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }\n .data th { font-size: var(--fs-sm); font-weight: 600; color: var(--dim); background: var(--sidebar); height: 22px; }\n .data tr:hover td { background: var(--hover); }\n .data .mono { font-family: var(--mono); font-size: var(--fs-sm); }\n\n /* key-value (frontmatter) */\n .kv td { padding: 1px 12px; font-family: var(--mono); font-size: var(--fs-sm); vertical-align: top; border-bottom: 1px solid var(--border); }\n .kv .k { width: 160px; color: #9cdcfe; white-space: nowrap; }\n .kv .v { color: #ce9178; white-space: pre-wrap; word-break: break-word; }\n .flag { font-size: 9px; font-weight: 700; margin-right: 4px; opacity: 0.5; }\n .flag.t { color: var(--ok); }\n .flag.s { color: var(--dim); }\n\n /* code block */\n .code {\n margin: 0; padding: 8px 12px; font: var(--fs-sm)/1.5 var(--mono);\n white-space: pre-wrap; word-break: break-word; color: var(--text);\n background: var(--bg); border: none;\n }\n\n /* meta row */\n .meta { display: flex; flex-wrap: wrap; font-size: var(--fs-sm); border-bottom: 1px solid var(--border); padding: 4px 0; }\n .meta dt { padding: 0 4px 0 12px; color: var(--dim); }\n .meta dt::after { content: \":\"; }\n .meta dd { padding: 0 12px 0 0; font-family: var(--mono); }\n\n /* misc */\n .dim { color: var(--dim); }\n .page-title { padding: 8px 12px 4px; font-size: 14px; font-weight: 400; }\n .page-sub { padding: 0 12px 8px; font-size: var(--fs-sm); color: var(--dim); }\n details summary { cursor: pointer; color: var(--accent); font-size: var(--fs-sm); }\n details[open] summary { margin-bottom: 4px; }\n .tag { font-size: var(--fs-sm); color: var(--dim); margin-left: 6px; }\n .tag-warn { color: var(--stale); }\n .tag-err { color: var(--missing); }\n </style>\n</head>\n<body>\n <div class=\"app\">\n <nav class=\"actbar\">\n <a href=\"/\" title=\"Overview\">⌂</a>\n <a href=\"/staleness\" title=\"Staleness\">⚠</a>\n </nav>\n <aside class=\"sidebar\">\n <div class=\"sidebar-head\">Types</div>\n <div class=\"sidebar-body\">${typeLinks || `<span class=\"dim\" style=\"padding:8px 12px\">—</span>`}</div>\n </aside>\n <div class=\"main\">\n <div class=\"content\">${body}</div>\n </div>\n </div>\n</body>\n</html>`;\n}\n\nfunction docTitleFromFrontmatter(frontmatter: Record<string, unknown>, enSlug: string): string {\n const title = frontmatter.title;\n if (typeof title === \"string\" && title.trim()) return title;\n return enSlug;\n}\n\n/** Start a local read-only Scribe studio (browser, staleness, document detail). */\nexport async function startStudio(\n project: ScribeProject,\n options: { port?: number; host?: string } = {},\n): Promise<void> {\n const app = new Hono();\n const config = project.config;\n\n app.get(\"/\", (c) => {\n const db = openStore(config, \"readonly\");\n const worklist = buildWorklist(config);\n const rows = project.listTypes().map((type) => {\n const enCount = type.list().length;\n const localeCells = config.locales\n .filter((locale) => locale !== config.defaultLocale)\n .map((locale) => {\n const translated = listTranslationsForLocale(db, type.id, locale).length;\n const stale = worklist.filter(\n (item) =>\n item.contentType === type.id && item.locale === locale && item.reason === \"stale\",\n ).length;\n const missing = worklist.filter(\n (item) =>\n item.contentType === type.id && item.locale === locale && item.reason === \"missing\",\n ).length;\n const tags = [\n stale ? `<span class=\"tag tag-warn\">${stale}s</span>` : \"\",\n missing ? `<span class=\"tag tag-err\">${missing}m</span>` : \"\",\n ].join(\"\");\n return `<td>${translated}${tags}</td>`;\n })\n .join(\"\");\n return `<tr>\n <td><a href=\"/type/${encodePathSegment(type.id)}\">${escapeHtml(type.config.label)}</a></td>\n <td class=\"dim\">${escapeHtml(type.id)}</td>\n <td>${enCount}</td>\n ${localeCells}\n </tr>`;\n });\n db.close();\n const localeHeaders = config.locales\n .filter((l) => l !== config.defaultLocale)\n .map((l) => `<th>${escapeHtml(l)}</th>`)\n .join(\"\");\n const html = `<div class=\"toolbar\">Overview</div>\n <table class=\"data\">\n <thead><tr><th>Type</th><th>ID</th><th>EN</th>${localeHeaders}</tr></thead>\n <tbody>${rows.join(\"\")}</tbody>\n </table>`;\n return c.html(renderLayout(\"Overview\", html, project));\n });\n\n app.get(\"/type/:id\", (c) => {\n const typeId = c.req.param(\"id\");\n const type = project.getType(typeId);\n if (!type) {\n return c.html(renderLayout(\"Not found\", `<div class=\"toolbar\">Unknown type</div>`, project), 404);\n }\n\n const db = openStore(config, \"readonly\");\n const locales = config.locales;\n const headerCells = locales\n .map((locale) => `<th>${escapeHtml(locale)}</th>`)\n .join(\"\");\n const rows = type\n .list()\n .map((doc) => {\n const title = docTitleFromFrontmatter(doc.frontmatter as Record<string, unknown>, doc.slug);\n const statusCells = locales\n .map((locale) => {\n const { status } = documentStatus(config, db, type, doc.slug, locale);\n return `<td>${statusDot(status)}</td>`;\n })\n .join(\"\");\n return `<tr>\n <td class=\"mono\"><a href=\"/type/${encodePathSegment(typeId)}/doc/${encodePathSegment(doc.slug)}\">${escapeHtml(doc.slug)}</a></td>\n <td>${escapeHtml(title)}</td>\n ${statusCells}\n </tr>`;\n })\n .join(\"\");\n db.close();\n\n const html = `<div class=\"toolbar\">\n <a href=\"/\">Overview</a><span class=\"sep\">›</span>${escapeHtml(type.config.label)}\n </div>\n <table class=\"data\">\n <thead><tr><th>Slug</th><th>Title</th>${headerCells}</tr></thead>\n <tbody>${rows || `<tr><td colspan=\"${2 + locales.length}\" class=\"dim\">No documents</td></tr>`}</tbody>\n </table>`;\n return c.html(renderLayout(type.config.label, html, project, { activeTypeId: typeId }));\n });\n\n app.get(\"/type/:id/doc/:enSlug\", (c) => {\n const typeId = c.req.param(\"id\");\n const enSlug = c.req.param(\"enSlug\");\n const locale = c.req.query(\"locale\") ?? config.defaultLocale;\n const showRaw = c.req.query(\"raw\") === \"1\";\n const type = project.getType(typeId);\n if (!type) {\n return c.html(renderLayout(\"Not found\", `<div class=\"toolbar\">Unknown type</div>`, project), 404);\n }\n\n const db = openStore(config, \"readonly\");\n const enDoc = readEnDocument(config, type.config, enSlug);\n if (!enDoc) {\n db.close();\n return c.html(\n renderLayout(\"Not found\", `<div class=\"toolbar\">Not found</div><p class=\"dim\" style=\"padding:12px\">${escapeHtml(enSlug)}</p>`, project, {\n activeTypeId: typeId,\n }),\n 404,\n );\n }\n\n const localeTabs = config.locales\n .map((loc) => {\n const { status } = documentStatus(config, db, type, enSlug, loc);\n const active = loc === locale ? \" active\" : \"\";\n const href = `/type/${encodePathSegment(typeId)}/doc/${encodePathSegment(enSlug)}?locale=${encodePathSegment(loc)}`;\n return `<a class=\"tab${active}\" href=\"${href}\">${escapeHtml(loc)} ${statusDot(status)}</a>`;\n })\n .join(\"\");\n\n let contentPanel = \"\";\n let metaPanel = \"\";\n let historyPanel = \"\";\n\n if (locale === config.defaultLocale) {\n contentPanel = `<div class=\"section\">\n <div class=\"section-head\">Frontmatter</div>\n <div class=\"section-body\">${renderFrontmatterTable(enDoc.frontmatter as Record<string, unknown>, type.config.schema)}</div>\n <div class=\"section-head\">Body</div>\n <pre class=\"code\">${escapeHtml(enDoc.content)}</pre>\n </div>`;\n } else {\n const translation = getTranslation(db, typeId, enSlug, locale);\n const { status, currentEnHash, storedEnHash } = documentStatus(config, db, type, enSlug, locale);\n\n if (translation) {\n const rawFrontmatter = JSON.parse(translation.frontmatter_json) as Record<string, unknown>;\n const displayFrontmatter = showRaw\n ? rawFrontmatter\n : mergeStructuralOntoLocale(rawFrontmatter, enDoc.frontmatter as Record<string, unknown>, type.config.schema);\n const rawToggle = showRaw\n ? `<span class=\"dim\"> · <a href=\"?locale=${encodePathSegment(locale)}\">merged</a></span>`\n : `<span class=\"dim\"> · <a href=\"?locale=${encodePathSegment(locale)}&raw=1\">raw</a></span>`;\n contentPanel = `<div class=\"section\">\n <div class=\"section-head\">Frontmatter${rawToggle}</div>\n <div class=\"section-body\">${renderFrontmatterTable(displayFrontmatter, type.config.schema)}</div>\n <div class=\"section-head\">Body</div>\n <pre class=\"code\">${escapeHtml(translation.body)}</pre>\n </div>`;\n metaPanel = `<dl class=\"meta\">\n <dt>status</dt><dd>${statusDot(status)}</dd>\n <dt>model</dt><dd>${escapeHtml(translation.model)}</dd>\n <dt>translated</dt><dd>${escapeHtml(translation.translated_at.slice(0, 19))}</dd>\n <dt>slug</dt><dd>${escapeHtml(translation.slug)}</dd>\n <dt>en_hash</dt><dd>${escapeHtml(currentEnHash?.slice(0, 12) ?? \"—\")} / ${escapeHtml(storedEnHash?.slice(0, 12) ?? \"—\")}</dd>\n </dl>`;\n const revisions = listRevisions(db, typeId, enSlug, locale);\n historyPanel = `<div class=\"section\">\n <div class=\"section-head\">History</div>\n <div class=\"section-body\">${renderRevisionTimeline(revisions)}</div>\n </div>`;\n } else {\n contentPanel = `<p class=\"dim\" style=\"padding:12px\">No translation for ${escapeHtml(locale)}.</p>`;\n metaPanel = `<dl class=\"meta\"><dt>status</dt><dd>${statusDot(status)}</dd></dl>`;\n }\n }\n\n db.close();\n\n const title = docTitleFromFrontmatter(enDoc.frontmatter as Record<string, unknown>, enSlug);\n const html = `<div class=\"toolbar\">\n <a href=\"/\">Overview</a><span class=\"sep\">›</span>\n <a href=\"/type/${encodePathSegment(typeId)}\">${escapeHtml(type.config.label)}</a><span class=\"sep\">›</span>\n <span>${escapeHtml(enSlug)}</span>\n </div>\n <div class=\"tabs\">${localeTabs}</div>\n ${metaPanel}\n ${contentPanel}\n ${historyPanel}`;\n\n return c.html(renderLayout(title, html, project, { activeTypeId: typeId }));\n });\n\n app.get(\"/staleness\", (c) => {\n const worklist = buildWorklist(config);\n const rows = worklist\n .slice(0, 500)\n .map((item) => {\n const href = `/type/${encodePathSegment(item.contentType)}/doc/${encodePathSegment(item.enSlug)}?locale=${encodePathSegment(item.locale)}`;\n return `<tr>\n <td>${escapeHtml(item.contentType)}</td>\n <td class=\"mono\"><a href=\"${href}\">${escapeHtml(item.enSlug)}</a></td>\n <td>${escapeHtml(item.locale)}</td>\n <td>${statusDot(item.reason === \"stale\" ? \"stale\" : \"missing\")}</td>\n </tr>`;\n })\n .join(\"\");\n const html = `<div class=\"toolbar\">Staleness <span class=\"dim\">· ${worklist.length} entries</span></div>\n <table class=\"data\">\n <thead><tr><th>Type</th><th>Slug</th><th>Locale</th><th>Status</th></tr></thead>\n <tbody>${rows || `<tr><td colspan=\"4\" class=\"dim\">All up to date</td></tr>`}</tbody>\n </table>`;\n return c.html(renderLayout(\"Staleness\", html, project));\n });\n\n app.get(\"/api/staleness-matrix\", (c) => {\n const worklist = buildWorklist(config);\n const matrix: Record<string, Record<string, number>> = {};\n for (const type of project.listTypes()) {\n matrix[type.id] = {};\n for (const locale of config.locales) {\n if (locale === config.defaultLocale) continue;\n matrix[type.id]![locale] = worklist.filter(\n (item) => item.contentType === type.id && item.locale === locale,\n ).length;\n }\n }\n return c.json(matrix);\n });\n\n const port = options.port ?? 3600;\n const host = options.host ?? \"127.0.0.1\";\n serve({ fetch: app.fetch, port, hostname: host }, () => {\n console.log(`Scribe studio listening on http://${host}:${port}`);\n });\n}\n"]}
|
package/dist/studio/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ScribeProject } from "../src/core/types.js";
|
|
2
|
-
/** Start a local read-only Scribe studio (browser, staleness,
|
|
2
|
+
/** Start a local read-only Scribe studio (browser, staleness, document detail). */
|
|
3
3
|
export declare function startStudio(project: ScribeProject, options?: {
|
|
4
4
|
port?: number;
|
|
5
5
|
host?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../studio/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../studio/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoC,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAoW5F,mFAAmF;AACnF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,OAAO,CAAC,IAAI,CAAC,CAiOf"}
|