feat(templates): T3 render() service (resolve+render, inline, version pin)
TemplateService.render(source, vars, opts) → { content, provenance }. Stored
key → resolve+render; inline → render without a DB row (key/version null);
explicit version pins. Provenance = {templateKey, version, locale, sha256(content)}.
10 tests (svc + repo).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -23,19 +23,26 @@ export class TemplateRepository {
|
||||
channel: IiosTemplateChannel,
|
||||
locale = 'en',
|
||||
scopeId?: string,
|
||||
version?: number,
|
||||
): Promise<IiosMessageTemplate> {
|
||||
// Scoped override first, then the global default — for both the pinned and highest-active paths.
|
||||
if (scopeId) {
|
||||
const scoped = await this.highest({ key, channel, locale, scopeId });
|
||||
const scoped = await this.pick({ key, channel, locale, scopeId }, version);
|
||||
if (scoped) return scoped;
|
||||
}
|
||||
const global = await this.highest({ key, channel, locale, scopeId: null });
|
||||
const global = await this.pick({ key, channel, locale, scopeId: null }, version);
|
||||
if (global) return global;
|
||||
throw new TemplateNotFoundError(key, channel, locale);
|
||||
}
|
||||
|
||||
private highest(where: { key: string; channel: IiosTemplateChannel; locale: string; scopeId: string | null }) {
|
||||
/** A pinned `version` fetches that exact version (the caller was explicit); otherwise the highest
|
||||
* active version — a retracted (inactive) newest version falls back to the last good one. */
|
||||
private pick(
|
||||
where: { key: string; channel: IiosTemplateChannel; locale: string; scopeId: string | null },
|
||||
version?: number,
|
||||
) {
|
||||
return this.prisma.iiosMessageTemplate.findFirst({
|
||||
where: { ...where, active: true },
|
||||
where: version != null ? { ...where, version } : { ...where, active: true },
|
||||
orderBy: { version: 'desc' },
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user