@arythmatic/connect-sdk
v0.1.5
Published
Embed Arythmatic Connect community workspaces into third-party platforms (LMS, CRM, portals) via a sandboxed iframe.
Maintainers
Readme
@arythmatic/connect-sdk
Thin JavaScript SDK for embedding Arythmatic Connect community workspaces into third-party platforms (LMS, CRM, portals, etc.) via a sandboxed <iframe>.
How it works
- Host platform (e.g. your Next.js LMS) includes the SDK and creates an
ArythmaticEmbedinstance. - The SDK injects an
<iframe>pointing to/embed/:workspace/:pathon the Arythmatic Community domain. - The iframe redirects to the canonical workspace route (
/w/:workspace/:path?embed=1). - The host sends the user's JWT to the iframe via
postMessage. - The iframe stores the token in
localStorage— the existing API client picks it up automatically. - No Auth0 redirect is triggered; the user is silently authenticated.
Tenant & workspace identification
| Resource | How it's identified |
|----------|---------------------|
| Workspace | URL slug (/w/:workspaceSlug) — passed explicitly in SDK options |
| Tenant | Preferred: iframe subdomain (acme.connect.arythmatic.cloud) — resolved by backend from hostname |
| Tenant (fallback) | tenant SDK option → cached in iframe → sent as X-Embed-Tenant header on every API call |
| User | Bearer <token> — validated by backend; LMS must issue JWTs the backend can verify |
Subdomain mode (recommended)
Set tenant and point baseUrl at your apex domain:
const embed = new ArythmaticEmbed({
container: '#community-root',
workspace: 'acme-corp',
tenant: 'acme', // iframe loads from acme.connect.arythmatic.cloud
baseUrl: 'https://connect.arythmatic.cloud',
token: lmsJwt,
});The iframe loads from https://acme.connect.arythmatic.cloud/embed/acme-corp. The backend resolves the tenant from the hostname exactly like the standalone app.
Central-domain mode (fallback)
If you must load from a single domain:
const embed = new ArythmaticEmbed({
container: '#community-root',
workspace: 'acme-corp',
tenant: 'acme', // forwarded to backend via X-Embed-Tenant header
baseUrl: 'https://connect.arythmatic.cloud',
token: lmsJwt,
});The iframe loads from https://connect.arythmatic.cloud/embed/acme-corp. The SDK passes tenant: 'acme' via postMessage; the iframe caches it in localStorage and the API client sends X-Embed-Tenant: acme on every authenticated request.
Backend contract
For the embed auth flow to work, the backend must:
- Validate LMS tokens — accept
Authorization: Bearer <lms-jwt>and verify the issuer/signature/audience. - Extract user identity from the LMS JWT claims (
sub,email, or a custom claim likearythmatic_user_id). - Map to a
CommunityUser— auto-provision or look up the user in the tenant's user pool. - Support
X-Embed-Tenant(for central-domain mode) — read the header whenorg_idisn't available from the JWT or hostname.
Install
Looking for framework-specific recipes (React, Next.js, Vue, Angular)? See NPM_INTEGRATION.md — focused step-by-step guide for integrators using the npm package.
Option A: npm (ES modules)
npm install @arythmatic/connect-sdkimport { ArythmaticEmbed } from '@arythmatic/connect-sdk';
const embed = new ArythmaticEmbed({
container: '#community-root',
workspace: 'acme-corp',
path: 'feed',
tenant: 'acme',
token: lmsJwt,
});
embed.mount();Option B: CDN (UMD via jsDelivr)
Any npm-published package is automatically mirrored by jsDelivr, so no
separate CDN deploy is needed. Pin to a specific version for production
to avoid surprise updates:
<script src="https://cdn.jsdelivr.net/npm/@arythmatic/[email protected]/dist/arythmatic-connect.umd.js"></script>
<script>
const embed = new ArythmaticConnectSDK.ArythmaticEmbed({
container: '#community-root',
workspace: 'acme-corp',
tenant: 'acme',
token: userJwt,
});
embed.mount();
</script>For demos / staging you can use a major-range pointer like
@arythmatic/connect-sdk@0 instead of @0.1.3, but production should
always pin to an exact version (and ideally use an integrity="sha384-…"
SRI hash — jsDelivr exposes one in the file's <details> panel).
API
new ArythmaticEmbed(options)
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| container | string \| HTMLElement | Yes | — | DOM element or selector where the iframe is injected. |
| workspace | string | Yes | — | Workspace slug to open. |
| path | string | No | — | Initial route inside the workspace (e.g. "channels/general"). |
| baseUrl | string | No | https://connect.arythmatic.cloud | Arythmatic Community base URL. |
| tenant | string | No | — | Tenant slug. Used for subdomain routing and X-Embed-Tenant header. |
| token | string | No | — | JWT access token from the host platform. |
| width | string | No | "100%" | Iframe width. |
| height | string | No | "600px" | Iframe height. |
| className | string | No | — | CSS class(es) for the iframe element. |
| style | object | No | — | Additional inline styles for the iframe. |
| onReady | () => void | No | — | Called when the iframe signals it is ready. |
| onAuthError | (err) => void | No | — | Called on auth failures inside the iframe. |
| onNavigate | (path) => void | No | — | Called when the user navigates inside the embed. |
| theme | ArythmaticEmbedTheme | No | — | Theme overrides — see Theming below. |
Instance methods
embed.setToken(token)— Update the auth token (e.g. after LMS refresh).embed.setTheme(theme)— Update the theme at runtime (field-by-field merge).embed.navigate(path)— Programmatically navigate the embed.embed.resize(width?, height?)— Adjust iframe dimensions.embed.destroy()— Remove the iframe and clean up listeners.
Theming
The embed exposes every colour the standalone app uses, plus a light/dark mode toggle.
const embed = new ArythmaticEmbed({
container: '#community-root',
workspace: 'acme-corp',
tenant: 'acme',
token: lmsJwt,
theme: {
mode: 'light', // 'light' | 'dark' | 'auto' (follow OS)
colors: {
accent: '#FF6600', // primary brand colour
bgSurface: '#ffffff',
textPrimary: '#111111',
},
// Per-mode overrides applied on top of `colors`. Use these when your
// brand needs different tones in light vs. dark mode.
dark: {
accent: '#FF8833', // brighter accent for legibility on dark
bgBase: '#0e0e10',
},
light: {
accent: '#CC4400', // deeper accent for contrast on light
},
},
});What you can override
theme.colors, theme.light, and theme.dark all accept the same shape (ArythmaticThemeColors):
| Group | Fields | Maps to |
|-------|--------|---------|
| Brand | accent, accentHover, accentSoft, accentRing, accentDeep | --color-accent, --color-accent-hover, --color-accent-soft, --color-accent-ring, --color-accent-deep |
| Surfaces | bgBase, bgSurface, bgElevated, bgHover | --color-bg-base, --color-bg-surface, --color-bg-elevated, --color-bg-hover |
| Text | textPrimary, textSecondary, textMuted | --color-text-primary, --color-text-secondary, --color-text-muted |
| Borders | borderSubtle, borderStrong | --color-border-subtle, --color-border-strong |
| Status | danger, success | --color-danger, --color-success |
Pass only the fields you want to change — everything else falls back to the embed's built-in palette for the current mode.
Smart defaults for accent
If you set only accent, the embed auto-derives the related variants so the UI stays coherent:
accentHover→ ~12% lighteraccentSoft→ 15% alphaaccentRing→ 35% alphaaccentDeep→ ~15% darker
Override any of these explicitly to pin them.
Merge order
Highest priority last:
- The embed's built-in palette for
mode theme.colorstheme.light(when mode is light) ortheme.dark(when mode is dark)
Runtime updates
embed.setTheme({ dark: { accent: '#ff6600' } }) merges field-by-field on top of the current theme. You can drop or change any single field without resending the rest.
Security
Every colour value must be a hex (#rgb / #rrggbb / #rrggbbaa), a CSS named colour, or rgb() / rgba() / hsl() / hsla() functional notation. Values containing ;, {, }, or HTML are rejected so the host can't inject arbitrary CSS through this prop. Unknown field names are silently dropped.
Build
cd sdk
npm install
npm run buildOutputs:
dist/arythmatic-connect.mjs— ES moduledist/arythmatic-connect.umd.js— UMD bundle (browser<script>tag)dist/index.d.ts— TypeScript declarations
Publishing
From the sdk/ directory:
npm login # one-time, npm credentials with publish rights on @arythmatic
npm version patch # or minor / major — bumps package.json + creates a git tag
npm publish # `prepublishOnly` rebuilds dist/ first; `publishConfig.access` makes it public
git push --follow-tags # push the version-bump commit + tagPre-publish dry-run to inspect what will go up:
npm pack --dry-runSecurity notes
- The SDK validates
postMessageorigins against the configuredbaseUrl(or tenant subdomain). - The iframe uses
sandbox="allow-same-origin allow-scripts allow-popups allow-forms". - The token is never exposed in the iframe URL; it travels exclusively via
postMessage. - Host platforms should issue short-lived JWTs scoped to the Arythmatic Community audience.
- The
X-Embed-Tenantheader is only sent when atenantoption was provided, preventing cross-tenant leakage.
