{"_id":"@alakazamworld/embed","name":"@alakazamworld/embed","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@alakazamworld/embed","version":"0.1.0","description":"Embed an Alakazam programmable world in your own site or app.","type":"module","main":"dist/embed.mjs","module":"dist/embed.mjs","types":"dist/index.d.ts","unpkg":"dist/embed.global.js","jsdelivr":"dist/embed.global.js","publishConfig":{"access":"public"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/embed.mjs"}},"scripts":{"build":"esbuild src/index.ts --bundle --format=esm --outfile=dist/embed.mjs && esbuild src/index.ts --bundle --format=iife --global-name=AlakazamEmbed --outfile=dist/embed.global.js && tsc --emitDeclarationOnly --project tsconfig.json","test":"node test/smoke.mjs"},"keywords":["alakazam","embed","game","world-model","sdk"],"license":"UNLICENSED","private":false,"devDependencies":{"esbuild":"^0.21.0","typescript":"^5.4.0"},"_id":"@alakazamworld/embed@0.1.0","gitHead":"8687154e86468fc6cc9b9f7701dfe324c3bdfb30","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-oJdHRNRmTn3OjFjUlTsh4j3acOKI4PVicthKzqDdXJm1cb/Wg+a/HQW/vG9+vMnn6JSG6Oxbs9QaWXmPFsfJcg==","shasum":"a7ced996e3d719d134ec4fce2e77d7c4b4253cff","tarball":"https://registry.npmjs.org/@alakazamworld/embed/-/embed-0.1.0.tgz","fileCount":6,"unpackedSize":26039,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCgucmyZT2bPL8/9bq+vV1QT2ZDWXOeENs5lzt0Rkhu1QIhAK5mcE2xKlJ3eIeaOAxNIC+zk7z5KzOS1hltXUtEJc81"}]},"_npmUser":{"name":"alakazamworld","email":"hugohl@hotmail.fr"},"directories":{},"maintainers":[{"name":"alakazamworld","email":"hugohl@hotmail.fr"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/embed_0.1.0_1782785397482_0.3365120644444741"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-30T02:09:57.379Z","0.1.0":"2026-06-30T02:09:57.608Z","modified":"2026-06-30T02:09:57.775Z"},"maintainers":[{"name":"alakazamworld","email":"hugohl@hotmail.fr"}],"description":"Embed an Alakazam programmable world in your own site or app.","keywords":["alakazam","embed","game","world-model","sdk"],"license":"UNLICENSED","readme":"# @alakazamworld/embed\n\nDrop an Alakazam **programmable world** into your own site or app — and react to\nits events to wire it into your own logic. Zero dependencies; works with any\nframework. Part of the [Alakazam programmable worlds API](https://docs.alakazam.gg).\n\n## Install\n\n```bash\nnpm install @alakazamworld/embed\n```\n\nOr via a script tag (auto-inits `[data-alakazam-slug]` elements):\n\n```html\n<div data-alakazam-slug=\"my-world\" data-alakazam-token=\"SESSION_TOKEN\"></div>\n<script src=\"https://cdn.alakazam.gg/embed.global.js\"></script>\n```\n\n## The two-token rule (important)\n\n- Your **secret** API key (`sk_…`) stays on **your server**. Never ship it to a browser.\n- Your server calls `POST /v1/sessions/token` with the secret key to mint a\n  **short-lived session token**, and hands *that* to the browser.\n- `@alakazamworld/embed` takes the session token and boots the world.\n\n```js\n// your backend\nconst r = await fetch(\"https://api.alakazam.gg/v1/sessions/token\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.ALAKAZAM_SECRET_KEY}`, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ worldId, playerIdentity: user.id, origin: \"https://yourgame.com\" }),\n});\nconst { token } = await r.json();   // send `token` to the browser\n```\n\n## Usage\n\n```js\nimport { createEmbed } from \"@alakazamworld/embed\";\n\nconst embed = createEmbed({\n  container: \"#game\",\n  slug: \"my-world\",\n  token,                       // the session token from your backend\n  theme: { colorPrimary: \"#86ffba\" },\n  onReady:   () => console.log(\"playing\"),\n  onChoice:  (c) => console.log(\"player chose\", c),\n  onEnding:  (e) => console.log(\"ending reached\", e),\n  onSessionEnded: () => console.log(\"session over\"),\n  // Re-authorization checkpoint: return a fresh token from your backend.\n  onTokenExpiring: async () => (await fetch(\"/api/alakazam-token\").then(r => r.json())).token,\n});\n\n// later\nembed.destroy();\n```\n\n## Theming (US-305)\n\nPass a `theme` to `createEmbed` and it is applied two ways so the player chrome\nis themed from the very first paint with no flash:\n\n- **At boot** — encoded as a base64-JSON `?theme=` query param on the iframe URL.\n- **At runtime** — call `embed.setTheme({ ... })` to post a `theme` message to\n  the running embed.\n\n```js\nembed.setTheme({ colorPrimary: \"#ff7ad9\", borderRadius: \"12px\" });\n```\n\nTheme tokens: `colorPrimary`, `colorBackground`, `colorText`, `fontFamily`,\n`borderRadius` (plus any extra string tokens).\n\n## Embedding security (US-307)\n\nThe `postMessage` bridge is **origin-validated on both ends**:\n\n- **Inbound** — a message is dropped unless `event.origin` is *exactly* the embed\n  base origin **and** it carries the SDK envelope (`source` marker + string\n  `type`). Cross-origin or malformed messages are ignored.\n- **Outbound** — token and theme posts target the exact embed origin\n  (`new URL(baseUrl).origin`), never the wildcard `'*'`, so a session token can\n  never leak to a navigated/foreign frame.\n\nYour **secret** key never touches the browser (see the two-token rule above);\nonly a short-lived session token does.\n\n> **Note:** the short-lived session token is delivered to the embed surface via\n> the iframe URL's `token` query param by design — so the embed host should avoid\n> logging that URL (or its `token` param) into request/access logs or analytics.\n> This is the documented tradeoff of URL-based token delivery.\n\n## Events\n\n`onReady`, `onChoice`, `onStateEntered`, `onEnding`, `onSessionEnded`,\n`onHeightChanged`, `onError`, `onTokenExpiring`. All are delivered over the\norigin-validated `postMessage` channel described above.\n\n## API\n\n`createEmbed(options) → { iframe, destroy(), setTheme(theme), sendToken(token) }`\n\nPure helpers (also exported, used internally and in the smoke test):\n`encodeTheme(obj) → string`, `isTrustedEmbedMessage(eventOrigin, expectedOrigin, data) → boolean`.\n\n## Test\n\n```bash\nnpm test   # node test/smoke.mjs — dependency-free, runs against the built dist\n```\n","readmeFilename":"README.md","_rev":"1-39e45f39f4f67307baa105ac933ae306"}