UNPKG

@omnizapi/connect

Version:

Omnizapi SDK for browser applications

93 lines (82 loc) • 4.4 kB
/** * Load after <button id="connect-btn" type="button">Connect channel</button> * and <button id="cancel-btn" type="button" disabled>Cancel authorization</button> * and <p id="status" role="status"></p>. * Negative results resolve; technical SDK errors reject. Neither is logged. * AbortSignal support is an Unreleased change; see the repository changelog. */ import Omnizapi, { OmnizapiError } from "@omnizapi/connect"; import type { ConnectionFailureReason, OmnizapiClient, OmnizapiErrorCode } from "@omnizapi/connect"; const failureMessages: Record<ConnectionFailureReason, string> = { cancelled: "Authorization was cancelled.", popup_closed: "The popup was closed before authorization finished.", not_completed: "Authorization was not completed.", invalid_channel: "This channel is invalid or unavailable.", origin_not_allowed: "This application origin is not authorized for the channel.", unsupported_channel: "This channel type is not supported.", }; const errorMessages: Record<OmnizapiErrorCode, string> = { BROWSER_REQUIRED: "Open this page in a browser to connect.", CONNECTION_IN_PROGRESS: "Finish the active attempt. If native Meta login is still awaiting its callback, wait for it or reload before another native attempt.", INVALID_CONFIGURATION: "Check the public key, environment, base URLs and any conflicting Meta app ID.", INVALID_OPTIONS: "Check the channel ID, timeout and AbortSignal options.", NETWORK_ERROR: "The connection service could not be reached. Please try again.", HTTP_ERROR: "The connection service rejected the request.", INVALID_RESPONSE: "The connection service returned an invalid response.", POPUP_BLOCKED: "Allow popups for this application, then click Connect again.", TIMEOUT: "The operation timed out. Only native Meta login still awaiting its callback blocks a native retry: wait for it or reload.", ABORTED: "Authorization was stopped by this application. If native Meta login is still awaiting its callback, wait for it or reload before another native attempt.", SDK_LOAD_FAILED: "The provider SDK could not load. Check browser restrictions.", PROVIDER_ERROR: "The provider reported an error. Check the provider configuration before retrying.", }; let client: OmnizapiClient | undefined; if (typeof document !== "undefined") { const button = document.querySelector<HTMLButtonElement>("#connect-btn"); const cancelButton = document.querySelector<HTMLButtonElement>("#cancel-btn"); const statusElement = document.querySelector<HTMLElement>("#status"); if (button && cancelButton && statusElement) { let controller: AbortController | undefined; cancelButton.addEventListener("click", () => { controller?.abort(); }); button.addEventListener("click", async () => { if (button.disabled) return; button.disabled = true; statusElement.textContent = "Connecting..."; try { client ??= Omnizapi.newClient({ publicKey: "your-public-key" }); controller = new AbortController(); cancelButton.disabled = false; const result = await client.connect({ channelId: "your-channel-id", signal: controller.signal, }); // Cancel only the SDK authorization, never imply a backend rollback. controller = undefined; cancelButton.disabled = true; if (!result.success) { statusElement.textContent = failureMessages[result.reason]; return; } // Your backend must authorize result.channelId for the session/tenant. const response = await fetch("/api/connect-channel", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(result), }); if (!response.ok) { statusElement.textContent = "The backend could not finalize the connection."; return; } statusElement.textContent = "Channel connected!"; } catch (error) { // Do not display/log raw errors: messages may contain sensitive URLs. statusElement.textContent = error instanceof OmnizapiError ? errorMessages[error.code] : "Could not confirm the connection. Check its backend status before retrying."; } finally { controller = undefined; cancelButton.disabled = true; button.disabled = false; } }); } }