feat(embeds): add embed.classroomio.com public widget host
Serve widgets from short public URLs via tenant-router with R2-backed assets and runtime API_URL injection, so copy-paste snippets hide infra paths. Update widget payloads, CSP, upload purge URLs, and dev-only API inject; document format/stage workflow in AGENTS.md and fix ui-prefix-check YAML syntax.
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
<script type="module">
|
||||
const params = new URLSearchParams(location.search);
|
||||
const key = params.get('key');
|
||||
const apiBaseUrl = params.get('api');
|
||||
|
||||
if (!key) {
|
||||
const note = document.createElement('p');
|
||||
@@ -31,15 +30,12 @@
|
||||
const widgetDiv = document.createElement('div');
|
||||
widgetDiv.setAttribute('data-cio-widget', 'course-widget');
|
||||
widgetDiv.setAttribute('data-widget-key', key);
|
||||
if (apiBaseUrl) {
|
||||
widgetDiv.setAttribute('data-api-base-url', apiBaseUrl);
|
||||
}
|
||||
mount.appendChild(widgetDiv);
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.async = true;
|
||||
script.type = 'module';
|
||||
script.src = './course-widget.js';
|
||||
script.src = window.location.pathname;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,20 +3,42 @@
|
||||
import type { TWidgetPayload } from '@cio/utils/validation/widget';
|
||||
import { CourseWidget } from '@cio/ui/custom/widget-layouts';
|
||||
|
||||
const DEFAULT_API_BASE_URL = 'https://api.classroomio.com';
|
||||
declare global {
|
||||
interface Window {
|
||||
CIO?: {
|
||||
apiBaseUrl?: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let { publicKey, apiBaseUrl = DEFAULT_API_BASE_URL }: { publicKey: string; apiBaseUrl?: string } = $props();
|
||||
let { publicKey, apiBaseUrl }: { publicKey: string; apiBaseUrl?: string } = $props();
|
||||
|
||||
let payload = $state<TWidgetPayload | null>(null);
|
||||
let errorMessage = $state('');
|
||||
|
||||
function resolveApiBaseUrl(): string {
|
||||
if (apiBaseUrl) {
|
||||
return apiBaseUrl.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
const fromWindow = typeof window !== 'undefined' ? window.CIO?.apiBaseUrl : undefined;
|
||||
if (fromWindow) {
|
||||
return fromWindow.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
async function loadPayload() {
|
||||
try {
|
||||
errorMessage = '';
|
||||
|
||||
const response = await fetch(
|
||||
`${(apiBaseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, '')}/widgets/${publicKey}/payload`
|
||||
);
|
||||
const apiOrigin = resolveApiBaseUrl();
|
||||
if (!apiOrigin) {
|
||||
throw new Error('Widget API URL is not configured');
|
||||
}
|
||||
|
||||
const response = await fetch(`${apiOrigin}/widgets/${publicKey}/payload`);
|
||||
const result = (await response.json()) as { success?: boolean; data?: TWidgetPayload; error?: string };
|
||||
|
||||
if (!response.ok || !result.success || !result.data) {
|
||||
|
||||
Reference in New Issue
Block a user