Compiler and runtime

Copy Markdown View Source

Authoring nodes

The host starts a supervised pool of bundled Node workers. Each worker runs the pinned official MJML compiler behind a framed JSON protocol. Requests have byte and time limits; a crashed or late worker is replaced without desynchronizing later requests.

children = [
  {Letterpress.Compiler.Supervisor,
   pool_size: 2,
   max_frame_bytes: 2_000_000}
]

Supervisor.start_link(children, strategy: :one_for_one)

Letterpress has no application callback and reads no global application configuration. The caller therefore chooses where the pool sits, how it is supervised, and whether a node starts one at all.

For more than one pool, give each a distinct name and select it per call:

children = [
  {Letterpress.Compiler.Supervisor, pool: MyApp.MarketingCompiler, pool_size: 2},
  {Letterpress.Compiler.Supervisor, pool: MyApp.TransactionalCompiler, pool_size: 4}
]

Letterpress.compile(profile, source, schema,
  compiler_pool: MyApp.TransactionalCompiler,
  compiler_timeout: 20_000
)

The worker launches with Node permission restrictions and a scrubbed environment. Permission mode is defense in depth, not a substitute for normal container or process isolation when template authors are untrusted.

Delivery nodes

Delivery-only nodes omit the compiler child. Valid stored artifacts still decode and render. Rendering runs in an isolated BEAM process with strict variables, output limits, collection/loop budgets, a timeout, and an allow-listed Liquid surface.

For email artifacts, pass the plain-text alternative as the :text compile option. It is schema-checked and stored with the HTML and subject so delivery renders all configured channels atomically.

Letterpress.render(artifact, values,
  timeout: 5_000,
  max_output_bytes: 1_000_000,
  max_heap_words: 2_000_000,
  subject_max_bytes: 998,
  allowed_url_schemes: ~w(http https mailto tel cid)
)

Tune limits from measured templates. Increasing a limit changes resource policy; it should be reviewed like any other capacity or abuse-control change.

Artifact rules

Artifacts are canonical JSON with compiler provenance and a content hash. Decode rejects missing, extra, or forged fields and unsupported versions. Keep the artifact whole; extracting only generated HTML discards schema and provenance needed for safe rendering and future migrations.