spur-monocle-manager
Version:
Wrapper for the Monocle SDK (Spur)
214 lines (213 loc) • 7.15 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
default: () => Monocle
});
module.exports = __toCommonJS(index_exports);
var MONOCLE_SCRIPT_URL = "https://mcl.spur.us/d/mcl.js";
var Monocle = class {
// Debug mode flag
/**
* @param options Configuration options, requiring a valid token
* @throws Error if no token is provided
*/
constructor(options) {
// Timeout for script loading
this._initialized = false;
this._readyPromise = null;
// Promise resolving when script is ready
this._script = null;
// <script> element reference
this._monocle = null;
// Global MCL object once loaded
this._eventTarget = null;
// EventTarget for custom events
this._handlers = /* @__PURE__ */ new Map();
if (!options.token) {
throw new Error("[Monocle] No token provided");
}
this.token = options.token;
this.initTimeout = options.initTimeout || 5e3;
if (options.debug) {
console.warn("[Monocle] Debug mode enabled");
}
this._debug = options.debug || false;
this._eventTarget = new EventTarget();
}
/**
* Dispatches a custom Monocle event on the internal EventTarget.
*/
_dispatch(event, detail) {
var _a;
(_a = this._eventTarget) == null ? void 0 : _a.dispatchEvent(new CustomEvent(event, { detail }));
}
/**
* Load the Monocle script into the document.
* Returns a promise that resolves when the script is loaded or rejects on failure or timeout.
*/
init() {
if (typeof window === "undefined") {
return Promise.reject(new Error("[Monocle] init() not supported in SSR"));
}
if (this._initialized) {
if (this._debug) {
console.warn("[Monocle] already initialized, init() ignored");
}
return this._readyPromise;
}
this._initialized = true;
this._readyPromise = new Promise((resolve, reject) => {
const timer = setTimeout(() => {
var _a;
if ((_a = this._script) == null ? void 0 : _a.parentNode) {
document.head.removeChild(this._script);
}
this._initialized = false;
this._readyPromise = null;
const err = new Error(`[Monocle] init() timeout after ${this.initTimeout} ms`);
this._dispatch("error", err);
reject(err);
}, this.initTimeout);
window._onAssessment = (jwt) => {
clearTimeout(timer);
this._dispatch("assessment", jwt);
resolve();
};
const script = document.createElement("script");
if (!this._script) {
this._script = script;
}
script.id = "_mcl";
script.async = true;
script.defer = true;
script.src = `${MONOCLE_SCRIPT_URL}?tk=${encodeURIComponent(this.token)}`;
script.addEventListener("load", () => {
this._monocle = window.MCL;
this._dispatch("load");
});
script.addEventListener("error", () => {
clearTimeout(timer);
try {
document.head.removeChild(script);
} catch {
}
this._initialized = false;
this._readyPromise = null;
const err = new Error("[Monocle] Failed to load script");
this._dispatch("error", err);
reject(err);
});
script.setAttribute("onassessment", "_onAssessment");
script.setAttribute("onbundle", "_onAssessment");
document.head.appendChild(script);
});
return this._readyPromise;
}
/**
* Returns the assessment JWT from Monocle.
* This method should only be called after the script is loaded and initialized.
* @throws Error if called on the server side or if no data is returned
*/
async getAssessment() {
if (typeof window === "undefined") {
throw new Error("[Monocle] getAssessment() is not available on the server side");
}
await this.init();
if (!this._monocle) {
throw new Error("[Monocle] MCL is not defined");
}
try {
await this._monocle.refresh();
const assessment = await this._monocle.getAssessment();
if (assessment) {
return assessment;
}
} catch (err) {
this._dispatch("error", err);
throw err;
}
const error = new Error("[Monocle] No data returned");
this._dispatch("error", error);
throw error;
}
/**
* Register an event listener for Monocle events.
*/
on(event, handler) {
if (typeof window === "undefined") return;
if (!this._eventTarget) this._eventTarget = new EventTarget();
const existing = this._handlers.get(event) || [];
if (existing.some((e) => e.original === handler)) {
if (this._debug) console.warn(`[Monocle] handler already registered for ${event}`);
return;
}
const wrapper = (e) => handler(e.detail);
existing.push({ original: handler, wrapper });
this._handlers.set(event, existing);
this._eventTarget.addEventListener(event, wrapper);
}
/**
* Unregister a previously added event listener.
*/
off(event, handler) {
if (typeof window === "undefined") return;
const list = this._handlers.get(event);
if (!list) return;
const remaining = [];
list.forEach(({ original, wrapper }) => {
if (original === handler) {
this._eventTarget.removeEventListener(event, wrapper);
} else {
remaining.push({ original, wrapper });
}
});
if (remaining.length) {
this._handlers.set(event, remaining);
} else {
this._handlers.delete(event);
}
}
/**
* Clean up the Monocle script and all associated resources.
*/
destroy() {
var _a, _b;
if (typeof window === "undefined" || !this._initialized) return;
(_b = (_a = this._script) == null ? void 0 : _a.parentNode) == null ? void 0 : _b.removeChild(this._script);
document.head.querySelectorAll("script").forEach((s) => {
if (s.src.includes("mcl.spur.us")) s.remove();
});
delete window._onAssessment;
delete window.MCL;
if (this._eventTarget) {
this._handlers.forEach((arr, event) => {
arr.forEach(({ wrapper }) => this._eventTarget.removeEventListener(event, wrapper));
});
}
this._eventTarget = null;
this._monocle = null;
this._script = null;
this._handlers.clear();
this._initialized = false;
this._readyPromise = null;
}
};
//# sourceMappingURL=index.cjs.map