@xenia-martech/mcp 1.2.0-dev.2 → 1.2.0-dev.3

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 CHANGED
@@ -31,6 +31,15 @@ After you choose how to get the SDK token, the assistant does the rest without s
31
31
  timeout and circuit breaker, consent from your cookie banner, and form conversions.
32
32
  - **Each journey** you name, in your real components: server-side with `{ fallback: null }` so an
33
33
  outage renders your default content; `track()` for event triggers.
34
+ - **Edge personalization** for a storefront whose journeys target pages (Personalization Resolve
35
+ with page patterns), using the SDK's helpers (`@xenia-martech/sdk-js` 1.2+) instead of hand-written
36
+ code. In Next.js: `xeniaEdgeProxy()` in `proxy.ts`, with your site's own facts and rewrites in its
37
+ hooks, plus `createManifestRoute()` and `createRevalidateRoute()` for the public manifest and
38
+ Xenia's storefront webhook. In any other proxy: `@xenia-martech/sdk-js/edge`. Personalized sections
39
+ get `data-xenia-slot` attributes for impressions and clicks. The browser client's `pageViews`,
40
+ `pageLeave`, `trail`, `navClicks` and `contentClicks` options handle tracking, and
41
+ `xeniaEdgeProxy({ debug, qa })` with `<XeniaDebugPanel />` shows what was decided on each page,
42
+ in development and QA only.
34
43
  - **Checks** — a type-check/build and `xenia_verify`, plus warnings about the journey itself (an
35
44
  A/B split that would show the same visitor different variants, a journey that's stopped) with the
36
45
  dashboard fix.
package/dist/bin.js CHANGED
@@ -159,7 +159,7 @@ Never ask the user to paste a Xenia password or SDK token into the conversation,
159
159
 
160
160
  When asked to set up the Xenia SDK in a project (or anything that implies it needs a token), first ask the user how they want to get the SDK token, before calling any tool that touches one: (1) you mint it now via xenia_mint_sdk_token \u2014 written straight to their env file, or (2) they create one themselves in the Xenia dashboard's API Tokens page and paste the resulting env var name in for you to wire up (never its value). Do not default to (1) without asking \u2014 some users are not comfortable with an assistant creating live credentials on their behalf. Run xenia_detect_stack first either way, so the question can name the right token type.
161
161
 
162
- After that, do the whole wiring yourself without asking per step: call xenia_setup_project and carry out every step it lists (create or merge the files, wire consent and forms), then for each journey the user wants, call xenia_get_journey and put its calls into the project's real components. Use the SDK's own helpers instead of hand-rolling them: in Next.js, xeniaProxy/xeniaServerFromNext from @xenia-martech/sdk-js/next; server webhooks with { fallback: null } (no try/catch or Promise.race); circuitBreaker in the config; for a journey with a Personalization Resolve trigger on a Contentful page, personalizePage(ref, { cms: contentfulAdapter(...), contentKey }) with the journey's content key (only that journey then decides the page) \u2014 the SDK fetches the page, so no CMS fetch or per-section resolve() calls in app code; ask the user the questions xenia_get_journey returns for it (where it runs, wait for all or show first) before writing it. Finish with a type-check/build and xenia_verify. Stop to ask only for the token choice, the CMS page questions, a production confirmation, or whether analytics needs consent when the site has no banner. Relay every warning from xenia_get_journey to the user: those are dashboard fixes (e.g. an A/B split that isn't sticky), not code changes.`});return vz(t,e),_z(t,e),$z(t,e),t}import{mkdir as R6,readFile as U6,writeFile as xz}from"node:fs/promises";import{homedir as o_}from"node:os";import{dirname as Z6,join as yo}from"node:path";import{fileURLToPath as M6}from"node:url";var a_={"claude-code":{id:"claude-code",displayName:"Claude Code",path:e=>yo(e,".mcp.json"),scope:"project",format:"json",serverKey:["mcpServers"]},cursor:{id:"cursor",displayName:"Cursor",path:e=>yo(e,".cursor","mcp.json"),scope:"project",format:"json",serverKey:["mcpServers"]},windsurf:{id:"windsurf",displayName:"Windsurf",path:()=>yo(o_(),".codeium","windsurf","mcp_config.json"),scope:"user",format:"json",serverKey:["mcpServers"]},copilot:{id:"copilot",displayName:"GitHub Copilot (VS Code)",path:e=>yo(e,".vscode","mcp.json"),scope:"project",format:"json",serverKey:["servers"]},codex:{id:"codex",displayName:"OpenAI Codex CLI",path:()=>yo(o_(),".codex","config.toml"),scope:"user",format:"toml",serverKey:["mcp_servers"]},gemini:{id:"gemini",displayName:"Gemini CLI",path:()=>yo(o_(),".gemini","settings.json"),scope:"user",format:"json",serverKey:["mcpServers"]}};async function kz(e){let t=s_(e,"--client"),n=s_(e,"--project")??process.cwd(),i=s_(e,"--base-url"),r=e.includes("--local");if(!t||!Object.hasOwn(a_,t)){process.stderr.write(`Specify a client: --client <${Object.keys(a_).join("|")}>
162
+ After that, do the whole wiring yourself without asking per step: call xenia_setup_project and carry out every step it lists (create or merge the files, wire consent and forms), then for each journey the user wants, call xenia_get_journey and put its calls into the project's real components. Use the SDK's own helpers instead of hand-rolling them: in Next.js, xeniaProxy/xeniaServerFromNext from @xenia-martech/sdk-js/next; server webhooks with { fallback: null } (no try/catch or Promise.race); circuitBreaker in the config; for a journey with a Personalization Resolve trigger on a Contentful page, personalizePage(ref, { cms: contentfulAdapter(...), contentKey }) with the journey's content key (only that journey then decides the page) \u2014 the SDK fetches the page, so no CMS fetch or per-section resolve() calls in app code; for a storefront proxy that personalizes pages through the edge decide API (journeys whose trigger lists pages), in Next.js xeniaEdgeProxy (proxy.ts) with createManifestRoute and createRevalidateRoute (the public manifest and storefront-webhook routes) from @xenia-martech/sdk-js/next, elsewhere the helpers in @xenia-martech/sdk-js/edge (createXeniaEdge, viewerGeo, edgeConsent, encodeVariant/decodeVariant, verifyWebhook, trimManifest, readTrail/withView) \u2014 never a hand-written manifest client, matcher, geo parser or HMAC check \u2014 with data-xenia-slot/-content-entry-id/-base-entry-id/-bucket on swapped sections for impressions, visitorCookie: { authoritative: true } when the proxy changes the visitor, and the client options pageViews, pageLeave, trail, navClicks and contentClicks instead of hand-written page-view, time-on-page or click tracking, and xeniaEdgeProxy's debug/qa options with <XeniaDebugPanel /> instead of a hand-made debug overlay or QA query parsing; ask the user the questions xenia_get_journey returns for it (where it runs, wait for all or show first) before writing it. Finish with a type-check/build and xenia_verify. Stop to ask only for the token choice, the CMS page questions, a production confirmation, or whether analytics needs consent when the site has no banner. Relay every warning from xenia_get_journey to the user: those are dashboard fixes (e.g. an A/B split that isn't sticky), not code changes.`});return vz(t,e),_z(t,e),$z(t,e),t}import{mkdir as R6,readFile as U6,writeFile as xz}from"node:fs/promises";import{homedir as o_}from"node:os";import{dirname as Z6,join as yo}from"node:path";import{fileURLToPath as M6}from"node:url";var a_={"claude-code":{id:"claude-code",displayName:"Claude Code",path:e=>yo(e,".mcp.json"),scope:"project",format:"json",serverKey:["mcpServers"]},cursor:{id:"cursor",displayName:"Cursor",path:e=>yo(e,".cursor","mcp.json"),scope:"project",format:"json",serverKey:["mcpServers"]},windsurf:{id:"windsurf",displayName:"Windsurf",path:()=>yo(o_(),".codeium","windsurf","mcp_config.json"),scope:"user",format:"json",serverKey:["mcpServers"]},copilot:{id:"copilot",displayName:"GitHub Copilot (VS Code)",path:e=>yo(e,".vscode","mcp.json"),scope:"project",format:"json",serverKey:["servers"]},codex:{id:"codex",displayName:"OpenAI Codex CLI",path:()=>yo(o_(),".codex","config.toml"),scope:"user",format:"toml",serverKey:["mcp_servers"]},gemini:{id:"gemini",displayName:"Gemini CLI",path:()=>yo(o_(),".gemini","settings.json"),scope:"user",format:"json",serverKey:["mcpServers"]}};async function kz(e){let t=s_(e,"--client"),n=s_(e,"--project")??process.cwd(),i=s_(e,"--base-url"),r=e.includes("--local");if(!t||!Object.hasOwn(a_,t)){process.stderr.write(`Specify a client: --client <${Object.keys(a_).join("|")}>
163
163
  `),process.exit(1);return}let o=a_[t],a=o.path(n),s=L6(o,i,r);if(await R6(Z6(a),{recursive:!0}),(o.format==="toml"?await F6(a,o,s):await V6(a,o,s))==="already-configured"){process.stdout.write(`Xenia is already configured for ${o.displayName} in ${a} \u2014 left unchanged.
164
164
  `);return}process.stdout.write([`Configured ${o.displayName}.`,` ${a}${o.scope==="user"?" (applies to all projects)":""}`,"",`Restart ${o.displayName}, then ask it to "connect my Xenia account".`,""].join(`
165
165
  `))}function L6(e,t,n){let i={XENIA_CLIENT_NAME:e.displayName};if(t&&(i.XENIA_BASE_URL=t),n){let r=M6(new URL("./bin.js",import.meta.url));return{command:process.execPath,args:[r],env:i}}return{command:"npx",args:["-y","@xenia-martech/mcp"],env:i}}async function V6(e,t,n){let i=await q6(e)??{},r=t.serverKey[0]??"mcpServers",o=wz(i[r])?i[r]:{};return o.xenia=n,i[r]=o,await xz(e,`${JSON.stringify(i,null,2)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenia-martech/mcp",
3
- "version": "1.2.0-dev.2",
3
+ "version": "1.2.0-dev.3",
4
4
  "description": "Connect your Xenia account to any AI coding assistant — journeys, trigger ids, content keys, and SDK setup over MCP",
5
5
  "license": "MIT",
6
6
  "type": "module",