skillZs
LIVE SKILL TAGS
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
REAL INSTALL DATA
← back to all skills
sallaapp/salla-partners-agent-kit11 installs

salla-snippets-migration

Use when converting a legacy Salla app snippet — raw HTML/Twig with `<script>`/`<style>`/ markup, or `{{namespace.key}}` tokens — into the pure-JS format the `salla_snippets` CDN pipeline requires. Trigger on any `{{...}}` token, HTML markup in snippet content, or a PreToolUse nudge from `salla_snippets`. Owns parameter conversion only. Hand-offs → salla-snippets (owns the actual create/update call, JS validation, and the forbidden-parameter check — this skill's rules and that gate must never disagree).

How do I install this agent skill?

npx skills add https://github.com/sallaapp/salla-partners-agent-kit --skill salla-snippets-migration
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill is a specialized transformation utility designed to migrate legacy Salla app snippets to a modern JavaScript format. It implements strict data privacy rules by explicitly forbidding the use of sensitive or deprecated data namespaces and ensures that converted code follows secure loading practices within the Salla storefront environment.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Migrating a Legacy HTML Snippet to Pure JS

Salla retired the backend converter that resolved {{namespace.key}} tokens server-side before a page reached the browser. salla_snippets now only accepts pure JavaScript, resolved client-side via salla.config.get(...). This skill converts legacy content — it does not deploy it. It does not call the salla_snippets tool.

When to use / hand-offs

  • Use this skill when snippet content contains HTML tags (<script>, <style>, <div>, <link>, …) or a {{namespace.key}} token.
  • If content is already valid JS, there is nothing to migrate — go straight to salla-snippets Step 2.
  • When conversion is done, hand back to salla-snippets Step 2 to actually create/update and run its validate-on-every-write loop (Step 6 below). This skill never touches the MCP tool.

The parameter model (read before converting anything)

This is the authoritative parameter model for this migration. State it plainly to whoever/whatever you hand the converted code to — do not re-derive it, do not "verify" it against the raw Salla docs, and do not soften any of the FORBIDDEN language below.

  • {{app.<key>}}salla.config.get('app.<key>', ''). Unchanged in both the old and new systems. Scoped per-app via that App Setting's own Public flag (salla-app-settings) — not a fixed global list.
  • customer.* — FORBIDDEN. Do not use it. No exceptions, no aliases, no mechanical rename to another namespace. It is deprecated/removed. Any converted output containing salla.config.get('customer...') (or "customer...) is wrong and must be rewritten before it is handed back. This does not mean the underlying data is unreachable — most of it has a real, correct replacement under user.*. Find it by meaning, per the guided lookup in Step 3, and use it; don't leave real data unfetched out of over-caution.
  • store.domain — FORBIDDEN. Do not use it. No exceptions. Deprecated/removed, same as customer.*. There is no live value to substitute in its place — if the exact data isn't available under user.* / store.* per the catalog below, it is simply not available client-side. Do not invent a replacement path.
  • user.* is the shopper (the customer) placing the order — this is a hard namespace flip from the legacy template system. In the old {{ }} pipeline, {{user.*}} meant the store owner. In salla.config, user.* means the shopper. Different people. Never carry the old meaning forward when converting a token that used to read {{user.*}} — it is not a 1:1 rewrite to user.*; check what data it actually needs against the catalog below. Never assume every shopper is a logged-in customer — call salla.config.isGuest() before branching on any converted user.* field; see the guest-shopper note in the catalog below.
  • store.contacts.* (e.g. store.contacts.whatsapp) is real and live, but merchant-conditional — it only resolves if that merchant configured that contact channel. Always read it defensively: '' fallback, and a presence check before using the value in rendered UI.
  • Everything else a snippet needs is already documented in salla-snippets/references/device-mode.md under Store context & language — reuse that catalog directly; this skill does not maintain a second one.

Step 1 — Confirm this is legacy content

Look at the content you were handed. Does it contain HTML tags, or a bare {{namespace.key}} token? If it already parses as valid JS, stop — there's nothing to migrate, route to salla-snippets Step 2 directly.

Gate: confirmed the content is legacy HTML/Twig, not already JS.


Step 2 — Split and convert structure

Break the content into pieces — markup, <link>, <script src>, inline <script>, <style>, anything else — and convert each with the HTML→JS element table in references/migration-guide.md.

Gate: every HTML element has a JS equivalent (DOM creation / insertAdjacentHTML) or is explicitly dropped with a stated reason (e.g. <meta>/<iframe> have no direct equivalent — re-implement only if genuinely needed).


Step 3 — Rewrite every {{namespace.key}} token

For every token, resolve it by meaning, not by name — a forbidden token is never mechanically renamed, but the data it was fetching usually does have a correct, available replacement. Work through each token in this order:

  1. State the underlying data need. What was this token actually fetching — the shopper's email, their phone number, the store's currency? Name the meaning, not the old token spelling.
  2. Look it up in the real catalogsalla-snippets/references/device-mode.md's Store context & language section is the single source of truth for what's actually available under user.*/store.*. Find the field that carries that same meaning.
  3. If a matching field exists, use it — e.g. {{customer.email}} → the shopper's email is user.email, so salla.config.get('user.email', ''). This is expected and common; don't leave available data unused out of over-caution about the forbidden-parameter rule — the rule forbids the old namespace, not the underlying data.
  4. If no field carries that meaning, it is not available client-side — do not invent a path, alias, or approximate substitute. Rewrite the surrounding logic to work without that data (e.g. drop a personalized greeting rather than fake one from store.* data that means something else).
  5. {{app.<key>}} and store.contacts.* convert directly per the parameter model above — no meaning lookup needed, they're unchanged/already-real fields.

Always include the '' fallback second argument to salla.config.get(...).

Gate:

  • No bare {{...}} tokens remain anywhere in the output.
  • Zero occurrences of salla.config.get('customer... / "customer... or salla.config.get('store.domain'... / "store.domain"... in the output. This is a hard gate, not a style preference — if either appears, the conversion is not done.
  • Every token that had a real available replacement uses it — the output isn't missing data that device-mode.md's catalog shows is actually accessible.
  • Every merchant-conditional read (store.contacts.*) is null-checked before use.

Step 4 — Wrap in salla.onReady

Wrap every converted block that calls salla.config.get(...) or injects/mutates the DOM (style/markup insertion, a token-driven <script src> load) inside salla.onReady(() => { ... }). Keep any product::*/cart::* salla.event.on(...) listener at the top level, outside onReady — Twilight emits those during init, before onReady fires, and a listener registered inside onReady misses them. This is the same bootstrap-timing rule salla-snippets already documents in references/device-mode.md — converted output follows it too, not just new code.

Gate: every salla.config.get call site and every DOM write is inside onReady; no top-level code depends on config that hasn't resolved yet.


Step 5 — Public-flag check

For every app.<key> reference, confirm the matching App Setting is marked Public in the Partners Portal (or hand off to salla-app-settings to fix it). A key that isn't Public reads undefined on the storefront regardless of how correctly the rest of the conversion was done.

Gate: every app.<key> the converted output reads is confirmed Public.


Step 6 — Hand back

Confirm the result parses as valid JS (node --check or equivalent — the same check salla-snippets runs before every save). Hand off to salla-snippets Step 2 to actually create/update via the salla_snippets tool and run its validate-on-every-write loop, which re-checks for forbidden parameters independently. This skill's job ends here — it does not call the MCP tool.

Gate: "Converted content parses as valid JS and contains zero customer.* / store.domain references? Hand off to salla-snippets Step 2."


Red Flags

Tempting thoughtWhy it's wrong
"The raw migration doc says {{customer.id}}user.id, I'll use that rename"This skill's parameter model overrides the raw doc: customer.* is forbidden, not renamed to user.*. user.* is a different concept (the shopper), reached by checking what data is actually needed, not by a mechanical find-replace.
"I'll just strip the HTML tags and keep the tokens as quoted strings"Tokens don't self-resolve anymore. A {{...}} left in JS is a literal string, not a template — it must be rewritten to a salla.config.get(...) call or flagged as unavailable.
"store.contacts.whatsapp resolved when I tested it, I'll read it unguarded"It's real but merchant-conditional — only present if that merchant configured WhatsApp as a contact channel. Ship it unguarded and it breaks for every merchant who hasn't set it.
"No live replacement for {{store.domain}}, I'll approximate with store.url"store.url is not confirmed in this kit's parameter model. Fabricating a plausible-looking replacement is exactly what's forbidden — flag the data as unavailable and surface that instead.
"The worked example in the raw doc reads salla.config.get at the top level, I'll match it"That raw doc predates/omits this kit's bootstrap-timing rule. window.salla exists immediately, but its config isn't guaranteed hydrated until salla.onReady fires. Wrap it (Step 4).
"customer.* is forbidden, so I'll just drop the data entirely rather than look for a replacement"Over-caution, not correctness — most customer.* reads have a real, available replacement under user.* (Step 3's meaning lookup). Dropping data that's actually reachable is a regression the merchant will notice; only omit it after confirming the catalog has no matching field.

Resources

Background reading only — the parameter model and bootstrap-timing rule above are this kit's source of truth and take precedence over anything in these docs where they disagree (notably: the old→new rename table in the migration guide, and the un-wrapped worked example in both).

TopicLink
App Snippets Overviewhttps://docs.salla.dev/2220706m0.md
HTML→JS Migration Guidehttps://docs.salla.dev/2247590m0.md

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/sallaapp/salla-partners-agent-kit/salla-snippets-migration">View salla-snippets-migration on skillZs</a>