feat(blocks): add typed personalization resolution
This commit is contained in:
1 parent
2428df6e78
commit
157eec7a78
9 files changed
+128
-12
No files matched your search
@@ -10,6 +10,8 @@ import {
|
||||
json,
|
||||
object,
|
||||
record,
|
||||
resolveDocumentVariables,
|
||||
safeUrl,
|
||||
string,
|
||||
validateDocument,
|
||||
type BlockDocument,
|
||||
@@ -69,7 +71,7 @@ const kind = defineDocumentKind({
|
||||
metadata: object({ title: string() }) as never,
|
||||
rootTypes: ["layout.root"],
|
||||
blocks: [root, text],
|
||||
variables: {},
|
||||
variables: { recipientName: "string" },
|
||||
breakpoints: {},
|
||||
capabilities: [],
|
||||
targets: ["html"],
|
||||
@@ -169,4 +171,23 @@ describe("dynamic blocks engine", () => {
|
||||
"a", "a-copy",
|
||||
]);
|
||||
});
|
||||
|
||||
test("validates and resolves typed personalization tokens", () => {
|
||||
const document = doc();
|
||||
document.root.slots.content = [
|
||||
{ ...text.create({ id: () => "personalized" }), props: { text: "Hi {{recipientName}}" } },
|
||||
];
|
||||
expect(validateDocument(document, kind, registry).ok).toBe(true);
|
||||
const resolved = resolveDocumentVariables(document, kind.variables, { recipientName: "Ada" });
|
||||
expect(resolved.ok && resolved.value.root.slots.content[0]?.props.text).toBe("Hi Ada");
|
||||
document.root.slots.content[0]!.props.text = "{{notAllowed}}";
|
||||
expect(validateDocument(document, kind, registry).ok).toBe(false);
|
||||
});
|
||||
|
||||
test("safe URLs allow bounded variable templates without allowing unsafe schemes", () => {
|
||||
const schema = safeUrl({ schemes: ["https"] });
|
||||
expect(schema.parse("https://example.com/u/{{recipientName}}").ok).toBe(true);
|
||||
expect(schema.parse("{{unsubscribeUrl}}").ok).toBe(true);
|
||||
expect(schema.parse("javascript:alert(1)").ok).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user