{"_id":"@alga-psa/extension-iframe-sdk","_rev":"3-4d03b5cb2de0beee0dedd39d1bcda233","name":"@alga-psa/extension-iframe-sdk","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@alga-psa/extension-iframe-sdk","version":"0.1.0","keywords":["alga-psa","extension","iframe","sdk","postMessage","react","hooks"],"license":"BSD-3-Clause","_id":"@alga-psa/extension-iframe-sdk@0.1.0","maintainers":[{"name":"robert-at-nineminds","email":"robert@nineminds.com"}],"homepage":"https://github.com/your-org/your-repo#readme","bugs":{"url":"https://github.com/your-org/your-repo/issues"},"dist":{"shasum":"6d7d818a6958e6f4a38ae9257ae753cbc268a361","tarball":"https://registry.npmjs.org/@alga-psa/extension-iframe-sdk/-/extension-iframe-sdk-0.1.0.tgz","fileCount":17,"integrity":"sha512-D2/Vhe3vpVE13YUU/AklmXq3k8RoEb3gwibIIlNB+ROfbLHc6tderx/gJhknurtdEz9WjoHbFHLYgFne2rnYMg==","signatures":[{"sig":"MEQCIGO43qptblNgT2JDsJbOu9SrNE2bmZtVnlzPJ1t/oL2NAiBR0NKlw7lNuHdmXBpmk3nBNrstZ63bVulOv87A7g5tAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22151},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"private":false,"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","test:watch":"vitest"},"_npmUser":{"name":"robert-at-nineminds","email":"robert@nineminds.com"},"repository":{"url":"git+https://github.com/your-org/your-repo.git","type":"git","directory":"sdk/extension-iframe-sdk"},"_npmVersion":"11.6.2","description":"Client SDK for building Alga iframe-delivered extensions (postMessage bridge + React hooks).","directories":{},"sideEffects":false,"_nodeVersion":"25.1.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^25.0.0","vitest":"^2.0.5","typescript":"^5.4.0","@types/node":"^22.4.1","@types/jsdom":"^21.1.7","@testing-library/react":"^16.0.0"},"peerDependencies":{"react":"^18 || ^19"},"_npmOperationalInternal":{"tmp":"tmp/extension-iframe-sdk_0.1.0_1767844459881_0.902160259412286","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@alga-psa/extension-iframe-sdk","version":"0.1.1","keywords":["alga-psa","extension","iframe","sdk","postMessage","react","hooks"],"license":"BSD-3-Clause","_id":"@alga-psa/extension-iframe-sdk@0.1.1","maintainers":[{"name":"robert-at-nineminds","email":"robert@nineminds.com"}],"homepage":"https://github.com/your-org/your-repo#readme","bugs":{"url":"https://github.com/your-org/your-repo/issues"},"dist":{"shasum":"5422743a40fa090e01504828c21a291d155beb08","tarball":"https://registry.npmjs.org/@alga-psa/extension-iframe-sdk/-/extension-iframe-sdk-0.1.1.tgz","fileCount":19,"integrity":"sha512-8TagPWmNIoRCdYOG2HVAxmdpa2WvV0wfQHdu/yEwlnk3WIXbHv2sOmX7dP77fizVJY3KgxJh+yUqXTrb/GFf/Q==","signatures":[{"sig":"MEUCIFiEQp3dAOlxqNqRM2Ly3jjWw/zVPpGp9FItgkjIB5RBAiEAtshoitaXOk1SrbbvSB5bxKc96wt7DjcHqab2Eg9Yjyc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26590},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"43e56821f06485b1f475f5b77af73c6e91ea5622","private":false,"scripts":{"test":"vitest run","build":"tsc -p tsconfig.json","test:watch":"vitest"},"_npmUser":{"name":"robert-at-nineminds","email":"robert@nineminds.com"},"repository":{"url":"git+https://github.com/your-org/your-repo.git","type":"git","directory":"sdk/extension-iframe-sdk"},"_npmVersion":"10.8.2","description":"Client SDK for building Alga iframe-delivered extensions (postMessage bridge + React hooks).","directories":{},"sideEffects":false,"_nodeVersion":"20.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","jsdom":"^25.0.0","vitest":"^4.0.18","esbuild":"^0.27.3","typescript":"^5.4.0","@types/node":"^22.4.1","@types/jsdom":"^21.1.7","@vitest/coverage-v8":"^4.0.18","@testing-library/react":"^16.0.0"},"peerDependencies":{"react":"^18 || ^19"},"_npmOperationalInternal":{"tmp":"tmp/extension-iframe-sdk_0.1.1_1770921378106_0.9227471959200528","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-01-08T03:54:19.770Z","modified":"2026-02-24T15:20:53.728Z","0.1.0":"2026-01-08T03:54:20.021Z","0.1.1":"2026-02-12T18:36:18.250Z"},"bugs":{"url":"https://github.com/your-org/your-repo/issues"},"license":"BSD-3-Clause","homepage":"https://github.com/your-org/your-repo#readme","keywords":["alga-psa","extension","iframe","sdk","postMessage","react","hooks"],"repository":{"url":"git+https://github.com/your-org/your-repo.git","type":"git","directory":"sdk/extension-iframe-sdk"},"description":"Client SDK for building Alga iframe-delivered extensions (postMessage bridge + React hooks).","maintainers":[{"email":"natallia@nineminds.com","name":"talya_b"},{"email":"robert@nineminds.com","name":"robert-at-nineminds"}],"readme":"# @alga/extension-iframe-sdk\n\nClient SDK for building UI extensions delivered via iframes. Provides a stable, versioned postMessage bridge, theme token injection, short‑lived auth session handling, and ergonomic React hooks.\n\nProtocol hardening:\n- Versioned message envelope with top-level fields: `alga: true`, `version: \"1\"`, `type`, optional `request_id`, and `payload`\n- Origin validation on both sides; child ignores events from unexpected origins\n- No usage of `targetOrigin=\"*\"` except in explicit dev/test guard\n- Sandbox guidance: default `sandbox=\"allow-scripts\"`; do not include `allow-same-origin` by default\n\n## Quick start\n\nA complete Vite + React + TS example is provided under:\n- `packages/extension-iframe-sdk/examples/vite-react`\n\nBuild and preview (from the example directory):\n- `pnpm dev` or `yarn dev`\n- `pnpm build` or `yarn build` (outputs static `index.html + assets/*`)\n\nEmbed the built app via iframe with a src of the form:\n- Relative (Rust host path): `/ext-ui/{extensionId}/{content_hash}/index.html?path=/desired/route`\n- Absolute (when `RUNNER_PUBLIC_BASE` is absolute): `${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/index.html?path=/desired/route`\n\nUse the host helper to construct the URL in the host:\n- `buildExtUiSrc()` (see host implementation in `ee/server/src/lib/extensions/ui/iframeBridge.ts`)\n\n## Parent-side (host) bootstrap usage\n\n```ts\n// Host-side (not part of this package): see ee/server/src/lib/extensions/ui/iframeBridge.ts\nconst iframe = document.querySelector('iframe#my-ext')!;\niframe.src = buildExtUiSrc(extensionId, contentHash, '/');\n\nbootstrapIframe({\n  iframe,\n  extensionId,\n  contentHash, // must match /^sha256:[0-9a-f]{64}$/i\n  initialPath: '/',\n  session: { token: shortLivedToken, expiresAt: '2025-01-01T00:00:00Z' },\n  themeTokens: {\n    '--alga-primary': '#2266ff',\n    '--alga-bg': '#fff',\n    '--alga-fg': '#111',\n  },\n  allowedOrigin: 'https://runner.example.com',\n  requestId: 'req-123',\n});\n```\n\n## Child-side (iframe app) usage with React hooks\n\n```tsx\nimport React, { useEffect } from 'react';\n// If you have @alga/ui-kit available locally, include tokens\n// import '@alga/ui-kit/tokens.css';\nimport { useBridge, useTheme, useAuthToken, useResize } from '@alga/extension-iframe-sdk';\n\nexport default function App() {\n  const bridge = useBridge();\n  const tokens = useTheme(bridge);\n  const token = useAuthToken(bridge);\n  const reportResize = useResize(bridge);\n\n  useEffect(() => {\n    reportResize(document.documentElement.scrollHeight);\n  }, [tokens, token, reportResize]);\n\n  return <div>My Extension UI</div>;\n}\n```\n\n## Canonical Handler Calls (UI -> own handler)\n\nUse `callHandlerJson` for extension UI calls instead of direct `fetch()` or manual postMessage wiring:\n\n```ts\nimport { IframeBridge, callHandlerJson } from '@alga-psa/extension-iframe-sdk';\n\nconst bridge = new IframeBridge({ devAllowWildcard: true });\nbridge.ready();\n\nconst status = await callHandlerJson(bridge, '/api/status');\n\nconst created = await callHandlerJson(bridge, '/api/items', {\n  method: 'POST',\n  body: { name: 'Sample' },\n});\n\nawait callHandlerJson(bridge, '/api/items/123', { method: 'DELETE' });\n```\n\n`callHandlerJson` forwards the requested HTTP method through the iframe bridge transport, so handlers can receive the intended method without embedding transport-specific override fields in route/body data.\n\n## Protocol\n- Parent → Child: `bootstrap` with `{ session, theme_tokens, navigation }`\n- Child → Parent: `ready`, `resize`, `navigate`\n- Envelope: `{ alga: true, version: \"1\", type, request_id?, payload }`\n\n## Security notes\n- Iframes should use `sandbox=\"allow-scripts\"` by default\n- Avoid `allow-same-origin` unless strictly necessary with additional CSP\n- Parent uses strict `targetOrigin`; child validates expected parent origin\n\n## License\nBSD-3-Clause — see `LICENSE`.\n","readmeFilename":"README.md"}