@prodigio-io/sdk 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +81 -68
- package/dist/index.mjs +81 -68
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -8,9 +8,6 @@ interface ProdigioInitConfig {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
badge?: {
|
|
10
10
|
position?: 'bottom-right' | 'bottom-left';
|
|
11
|
-
/** Only inject the badge when the current page path starts with one of these strings.
|
|
12
|
-
* e.g. ['/careers'] — badge appears on /careers and /careers/job-id but not on / or /about */
|
|
13
|
-
paths?: string[];
|
|
14
11
|
};
|
|
15
12
|
}
|
|
16
13
|
interface SalaryRange {
|
|
@@ -119,6 +116,7 @@ declare class Prodigio {
|
|
|
119
116
|
name: string;
|
|
120
117
|
content: string;
|
|
121
118
|
};
|
|
119
|
+
static destroy(): void;
|
|
122
120
|
static init(config: ProdigioInitConfig): Promise<void>;
|
|
123
121
|
}
|
|
124
122
|
|
package/dist/index.d.ts
CHANGED
|
@@ -8,9 +8,6 @@ interface ProdigioInitConfig {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
badge?: {
|
|
10
10
|
position?: 'bottom-right' | 'bottom-left';
|
|
11
|
-
/** Only inject the badge when the current page path starts with one of these strings.
|
|
12
|
-
* e.g. ['/careers'] — badge appears on /careers and /careers/job-id but not on / or /about */
|
|
13
|
-
paths?: string[];
|
|
14
11
|
};
|
|
15
12
|
}
|
|
16
13
|
interface SalaryRange {
|
|
@@ -119,6 +116,7 @@ declare class Prodigio {
|
|
|
119
116
|
name: string;
|
|
120
117
|
content: string;
|
|
121
118
|
};
|
|
119
|
+
static destroy(): void;
|
|
122
120
|
static init(config: ProdigioInitConfig): Promise<void>;
|
|
123
121
|
}
|
|
124
122
|
|
package/dist/index.js
CHANGED
|
@@ -68,7 +68,6 @@ async function verifyBadgeToken(token) {
|
|
|
68
68
|
const parts = token.split(".");
|
|
69
69
|
if (parts.length !== 3) return null;
|
|
70
70
|
const [headerB64, payloadB64, sigB64] = parts;
|
|
71
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
72
71
|
const signature = base64urlToArrayBuffer(sigB64);
|
|
73
72
|
const keyData = pemToArrayBuffer(PRODIGIO_PUBLIC_KEY_PEM);
|
|
74
73
|
const publicKey = await crypto.subtle.importKey(
|
|
@@ -78,12 +77,11 @@ async function verifyBadgeToken(token) {
|
|
|
78
77
|
false,
|
|
79
78
|
["verify"]
|
|
80
79
|
);
|
|
81
|
-
const encoder = new TextEncoder();
|
|
82
80
|
const valid = await crypto.subtle.verify(
|
|
83
81
|
"RSASSA-PKCS1-v1_5",
|
|
84
82
|
publicKey,
|
|
85
83
|
signature,
|
|
86
|
-
|
|
84
|
+
new TextEncoder().encode(`${headerB64}.${payloadB64}`)
|
|
87
85
|
);
|
|
88
86
|
if (!valid) return null;
|
|
89
87
|
const claims = JSON.parse(atob(payloadB64.replace(/-/g, "+").replace(/_/g, "/")));
|
|
@@ -106,25 +104,13 @@ function injectBadge(position = "bottom-right") {
|
|
|
106
104
|
el.setAttribute("data-prodigio-badge", "true");
|
|
107
105
|
el.setAttribute("aria-label", "Hiring powered by Prodigio");
|
|
108
106
|
el.style.cssText = `
|
|
109
|
-
position: fixed;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
display: inline-flex;
|
|
114
|
-
align-items: center;
|
|
115
|
-
gap: 6px;
|
|
116
|
-
padding: 6px 10px;
|
|
117
|
-
background: #ffffff;
|
|
118
|
-
border: 1px solid #e5e5e5;
|
|
119
|
-
border-radius: 20px;
|
|
120
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
107
|
+
position: fixed; bottom: 20px; ${side}
|
|
108
|
+
z-index: 2147483647; display: inline-flex; align-items: center; gap: 6px;
|
|
109
|
+
padding: 6px 10px; background: #ffffff; border: 1px solid #e5e5e5;
|
|
110
|
+
border-radius: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
121
111
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
122
|
-
font-size: 11px;
|
|
123
|
-
|
|
124
|
-
color: #666666;
|
|
125
|
-
text-decoration: none;
|
|
126
|
-
cursor: pointer;
|
|
127
|
-
transition: box-shadow 0.15s ease;
|
|
112
|
+
font-size: 11px; font-weight: 500; color: #666666;
|
|
113
|
+
text-decoration: none; cursor: pointer; transition: box-shadow 0.15s ease;
|
|
128
114
|
`;
|
|
129
115
|
el.innerHTML = `
|
|
130
116
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -149,20 +135,48 @@ function removeBadge() {
|
|
|
149
135
|
}
|
|
150
136
|
function cacheToken(apiKey, token, badgeExemptUntil, configVersion) {
|
|
151
137
|
try {
|
|
152
|
-
|
|
153
|
-
localStorage.setItem(`${BADGE_CACHE_KEY}_${apiKey}`, JSON.stringify(entry));
|
|
138
|
+
localStorage.setItem(`${BADGE_CACHE_KEY}_${apiKey}`, JSON.stringify({ token, badgeExemptUntil, configVersion, cachedAt: Date.now() }));
|
|
154
139
|
} catch {
|
|
155
140
|
}
|
|
156
141
|
}
|
|
157
142
|
function getCachedToken(apiKey) {
|
|
158
143
|
try {
|
|
159
144
|
const raw = localStorage.getItem(`${BADGE_CACHE_KEY}_${apiKey}`);
|
|
160
|
-
|
|
161
|
-
return JSON.parse(raw);
|
|
145
|
+
return raw ? JSON.parse(raw) : null;
|
|
162
146
|
} catch {
|
|
163
147
|
return null;
|
|
164
148
|
}
|
|
165
149
|
}
|
|
150
|
+
var _routeWatcherInstalled = false;
|
|
151
|
+
var _routeChangeCallbacks = [];
|
|
152
|
+
function installRouteWatcher() {
|
|
153
|
+
if (_routeWatcherInstalled || typeof window === "undefined") return;
|
|
154
|
+
_routeWatcherInstalled = true;
|
|
155
|
+
const dispatch = () => _routeChangeCallbacks.forEach((cb) => cb());
|
|
156
|
+
const orig = {
|
|
157
|
+
push: history.pushState.bind(history),
|
|
158
|
+
replace: history.replaceState.bind(history)
|
|
159
|
+
};
|
|
160
|
+
history.pushState = (...args) => {
|
|
161
|
+
orig.push(...args);
|
|
162
|
+
dispatch();
|
|
163
|
+
};
|
|
164
|
+
history.replaceState = (...args) => {
|
|
165
|
+
orig.replace(...args);
|
|
166
|
+
dispatch();
|
|
167
|
+
};
|
|
168
|
+
window.addEventListener("popstate", dispatch);
|
|
169
|
+
window.addEventListener("hashchange", dispatch);
|
|
170
|
+
}
|
|
171
|
+
var _initialized = false;
|
|
172
|
+
function normalizePath(p) {
|
|
173
|
+
return p.replace(/\/$/, "").split("?")[0];
|
|
174
|
+
}
|
|
175
|
+
function pathMatches(current, careersPath) {
|
|
176
|
+
const c = normalizePath(current);
|
|
177
|
+
const target = normalizePath(careersPath);
|
|
178
|
+
return c === target || c.startsWith(target + "/");
|
|
179
|
+
}
|
|
166
180
|
var _Prodigio = class _Prodigio {
|
|
167
181
|
constructor(config) {
|
|
168
182
|
// ── Jobs ──────────────────────────────────────────────────────────────────
|
|
@@ -206,9 +220,7 @@ var _Prodigio = class _Prodigio {
|
|
|
206
220
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
207
221
|
url.searchParams.set("key", this.apiKey);
|
|
208
222
|
if (params) {
|
|
209
|
-
for (const [k, v] of Object.entries(params))
|
|
210
|
-
if (v !== void 0) url.searchParams.set(k, v);
|
|
211
|
-
}
|
|
223
|
+
for (const [k, v] of Object.entries(params)) if (v !== void 0) url.searchParams.set(k, v);
|
|
212
224
|
}
|
|
213
225
|
const res = await fetch(url.toString());
|
|
214
226
|
if (!res.ok) {
|
|
@@ -243,75 +255,75 @@ var _Prodigio = class _Prodigio {
|
|
|
243
255
|
}
|
|
244
256
|
static badge(poweredBy) {
|
|
245
257
|
const pb = poweredBy != null ? poweredBy : _Prodigio.POWERED_BY;
|
|
246
|
-
return {
|
|
247
|
-
href: pb.url,
|
|
248
|
-
"data-prodigio-badge": "true",
|
|
249
|
-
target: "_blank",
|
|
250
|
-
rel: "noopener noreferrer",
|
|
251
|
-
text: pb.text
|
|
252
|
-
};
|
|
258
|
+
return { href: pb.url, "data-prodigio-badge": "true", target: "_blank", rel: "noopener noreferrer", text: pb.text };
|
|
253
259
|
}
|
|
254
260
|
static meta() {
|
|
255
261
|
return { name: "prodigio-badge", content: "true" };
|
|
256
262
|
}
|
|
257
|
-
// ──
|
|
263
|
+
// ── destroy() ─────────────────────────────────────────────────────────────
|
|
264
|
+
static destroy() {
|
|
265
|
+
removeBadge();
|
|
266
|
+
_initialized = false;
|
|
267
|
+
}
|
|
268
|
+
// ── init() ────────────────────────────────────────────────────────────────
|
|
258
269
|
static async init(config) {
|
|
259
270
|
var _a;
|
|
260
271
|
if (typeof window === "undefined") return;
|
|
272
|
+
if (_initialized) return;
|
|
273
|
+
_initialized = true;
|
|
261
274
|
const { key, badgeToken, baseUrl = DEFAULT_BASE_URL, badge: badgeConfig } = config;
|
|
262
275
|
const position = (_a = badgeConfig == null ? void 0 : badgeConfig.position) != null ? _a : "bottom-right";
|
|
263
|
-
const paths = badgeConfig == null ? void 0 : badgeConfig.paths;
|
|
264
|
-
if (paths && paths.length > 0) {
|
|
265
|
-
const currentPath = window.location.pathname;
|
|
266
|
-
if (!paths.some((p) => currentPath === p || currentPath.startsWith(p + "/"))) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const hostname = window.location.hostname;
|
|
271
276
|
const cached = getCachedToken(key);
|
|
272
|
-
let bestToken = null;
|
|
273
|
-
let bestTokenRaw = null;
|
|
274
277
|
const [initClaims, cachedClaims] = await Promise.all([
|
|
275
278
|
badgeToken ? verifyBadgeToken(badgeToken) : Promise.resolve(null),
|
|
276
279
|
cached ? verifyBadgeToken(cached.token) : Promise.resolve(null)
|
|
277
280
|
]);
|
|
281
|
+
let bestToken = null;
|
|
278
282
|
if (initClaims && cachedClaims) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
} else {
|
|
283
|
-
bestToken = cachedClaims;
|
|
284
|
-
bestTokenRaw = cached.token;
|
|
285
|
-
}
|
|
286
|
-
} else if (initClaims) {
|
|
287
|
-
bestToken = initClaims;
|
|
288
|
-
bestTokenRaw = badgeToken;
|
|
289
|
-
} else if (cachedClaims) {
|
|
290
|
-
bestToken = cachedClaims;
|
|
291
|
-
bestTokenRaw = cached.token;
|
|
283
|
+
bestToken = new Date(initClaims.badgeExemptUntil) >= new Date(cachedClaims.badgeExemptUntil) ? initClaims : cachedClaims;
|
|
284
|
+
} else {
|
|
285
|
+
bestToken = initClaims != null ? initClaims : cachedClaims;
|
|
292
286
|
}
|
|
287
|
+
const hostname = window.location.hostname;
|
|
293
288
|
const domainAllowed = bestToken ? bestToken.allowedDomains.length === 0 || bestToken.allowedDomains.includes(hostname) : true;
|
|
294
289
|
const isExempt = bestToken !== null && !bestToken.badgeRequired && domainAllowed;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const cacheAge = Date.now() - cached.cachedAt;
|
|
299
|
-
if (cacheAge < GRACE_PERIOD_MS) {
|
|
290
|
+
let careersPath = null;
|
|
291
|
+
function evaluateBadge() {
|
|
292
|
+
if (isExempt) {
|
|
300
293
|
removeBadge();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (careersPath) {
|
|
297
|
+
if (pathMatches(window.location.pathname, careersPath)) {
|
|
298
|
+
injectBadge(position);
|
|
299
|
+
} else {
|
|
300
|
+
removeBadge();
|
|
301
|
+
}
|
|
301
302
|
} else {
|
|
303
|
+
if (!bestToken && cached) {
|
|
304
|
+
const cacheAge = Date.now() - cached.cachedAt;
|
|
305
|
+
if (cacheAge < GRACE_PERIOD_MS) {
|
|
306
|
+
removeBadge();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
302
310
|
injectBadge(position);
|
|
303
311
|
}
|
|
304
|
-
} else {
|
|
305
|
-
injectBadge(position);
|
|
306
312
|
}
|
|
313
|
+
evaluateBadge();
|
|
314
|
+
installRouteWatcher();
|
|
315
|
+
_routeChangeCallbacks.push(evaluateBadge);
|
|
307
316
|
setTimeout(async () => {
|
|
308
317
|
var _a2, _b;
|
|
309
318
|
try {
|
|
310
319
|
const res = await fetch(`${baseUrl}/api/sdk/config?key=${encodeURIComponent(key)}`);
|
|
311
320
|
if (!res.ok) return;
|
|
312
321
|
const data = await res.json();
|
|
322
|
+
if (data.careersPath !== void 0) {
|
|
323
|
+
careersPath = data.careersPath;
|
|
324
|
+
}
|
|
313
325
|
if (data.badgeRequired) {
|
|
314
|
-
|
|
326
|
+
evaluateBadge();
|
|
315
327
|
return;
|
|
316
328
|
}
|
|
317
329
|
if (data.badgeToken) {
|
|
@@ -321,12 +333,13 @@ var _Prodigio = class _Prodigio {
|
|
|
321
333
|
removeBadge();
|
|
322
334
|
}
|
|
323
335
|
}
|
|
336
|
+
evaluateBadge();
|
|
324
337
|
} catch {
|
|
325
338
|
}
|
|
326
339
|
}, 0);
|
|
327
340
|
}
|
|
328
341
|
};
|
|
329
|
-
// ── Badge
|
|
342
|
+
// ── Badge static helpers ──────────────────────────────────────────────────
|
|
330
343
|
_Prodigio.POWERED_BY = {
|
|
331
344
|
text: "Hiring powered by Prodigio",
|
|
332
345
|
url: "https://prodigio.io"
|
package/dist/index.mjs
CHANGED
|
@@ -42,7 +42,6 @@ async function verifyBadgeToken(token) {
|
|
|
42
42
|
const parts = token.split(".");
|
|
43
43
|
if (parts.length !== 3) return null;
|
|
44
44
|
const [headerB64, payloadB64, sigB64] = parts;
|
|
45
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
46
45
|
const signature = base64urlToArrayBuffer(sigB64);
|
|
47
46
|
const keyData = pemToArrayBuffer(PRODIGIO_PUBLIC_KEY_PEM);
|
|
48
47
|
const publicKey = await crypto.subtle.importKey(
|
|
@@ -52,12 +51,11 @@ async function verifyBadgeToken(token) {
|
|
|
52
51
|
false,
|
|
53
52
|
["verify"]
|
|
54
53
|
);
|
|
55
|
-
const encoder = new TextEncoder();
|
|
56
54
|
const valid = await crypto.subtle.verify(
|
|
57
55
|
"RSASSA-PKCS1-v1_5",
|
|
58
56
|
publicKey,
|
|
59
57
|
signature,
|
|
60
|
-
|
|
58
|
+
new TextEncoder().encode(`${headerB64}.${payloadB64}`)
|
|
61
59
|
);
|
|
62
60
|
if (!valid) return null;
|
|
63
61
|
const claims = JSON.parse(atob(payloadB64.replace(/-/g, "+").replace(/_/g, "/")));
|
|
@@ -80,25 +78,13 @@ function injectBadge(position = "bottom-right") {
|
|
|
80
78
|
el.setAttribute("data-prodigio-badge", "true");
|
|
81
79
|
el.setAttribute("aria-label", "Hiring powered by Prodigio");
|
|
82
80
|
el.style.cssText = `
|
|
83
|
-
position: fixed;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
display: inline-flex;
|
|
88
|
-
align-items: center;
|
|
89
|
-
gap: 6px;
|
|
90
|
-
padding: 6px 10px;
|
|
91
|
-
background: #ffffff;
|
|
92
|
-
border: 1px solid #e5e5e5;
|
|
93
|
-
border-radius: 20px;
|
|
94
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
81
|
+
position: fixed; bottom: 20px; ${side}
|
|
82
|
+
z-index: 2147483647; display: inline-flex; align-items: center; gap: 6px;
|
|
83
|
+
padding: 6px 10px; background: #ffffff; border: 1px solid #e5e5e5;
|
|
84
|
+
border-radius: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
95
85
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
96
|
-
font-size: 11px;
|
|
97
|
-
|
|
98
|
-
color: #666666;
|
|
99
|
-
text-decoration: none;
|
|
100
|
-
cursor: pointer;
|
|
101
|
-
transition: box-shadow 0.15s ease;
|
|
86
|
+
font-size: 11px; font-weight: 500; color: #666666;
|
|
87
|
+
text-decoration: none; cursor: pointer; transition: box-shadow 0.15s ease;
|
|
102
88
|
`;
|
|
103
89
|
el.innerHTML = `
|
|
104
90
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -123,20 +109,48 @@ function removeBadge() {
|
|
|
123
109
|
}
|
|
124
110
|
function cacheToken(apiKey, token, badgeExemptUntil, configVersion) {
|
|
125
111
|
try {
|
|
126
|
-
|
|
127
|
-
localStorage.setItem(`${BADGE_CACHE_KEY}_${apiKey}`, JSON.stringify(entry));
|
|
112
|
+
localStorage.setItem(`${BADGE_CACHE_KEY}_${apiKey}`, JSON.stringify({ token, badgeExemptUntil, configVersion, cachedAt: Date.now() }));
|
|
128
113
|
} catch {
|
|
129
114
|
}
|
|
130
115
|
}
|
|
131
116
|
function getCachedToken(apiKey) {
|
|
132
117
|
try {
|
|
133
118
|
const raw = localStorage.getItem(`${BADGE_CACHE_KEY}_${apiKey}`);
|
|
134
|
-
|
|
135
|
-
return JSON.parse(raw);
|
|
119
|
+
return raw ? JSON.parse(raw) : null;
|
|
136
120
|
} catch {
|
|
137
121
|
return null;
|
|
138
122
|
}
|
|
139
123
|
}
|
|
124
|
+
var _routeWatcherInstalled = false;
|
|
125
|
+
var _routeChangeCallbacks = [];
|
|
126
|
+
function installRouteWatcher() {
|
|
127
|
+
if (_routeWatcherInstalled || typeof window === "undefined") return;
|
|
128
|
+
_routeWatcherInstalled = true;
|
|
129
|
+
const dispatch = () => _routeChangeCallbacks.forEach((cb) => cb());
|
|
130
|
+
const orig = {
|
|
131
|
+
push: history.pushState.bind(history),
|
|
132
|
+
replace: history.replaceState.bind(history)
|
|
133
|
+
};
|
|
134
|
+
history.pushState = (...args) => {
|
|
135
|
+
orig.push(...args);
|
|
136
|
+
dispatch();
|
|
137
|
+
};
|
|
138
|
+
history.replaceState = (...args) => {
|
|
139
|
+
orig.replace(...args);
|
|
140
|
+
dispatch();
|
|
141
|
+
};
|
|
142
|
+
window.addEventListener("popstate", dispatch);
|
|
143
|
+
window.addEventListener("hashchange", dispatch);
|
|
144
|
+
}
|
|
145
|
+
var _initialized = false;
|
|
146
|
+
function normalizePath(p) {
|
|
147
|
+
return p.replace(/\/$/, "").split("?")[0];
|
|
148
|
+
}
|
|
149
|
+
function pathMatches(current, careersPath) {
|
|
150
|
+
const c = normalizePath(current);
|
|
151
|
+
const target = normalizePath(careersPath);
|
|
152
|
+
return c === target || c.startsWith(target + "/");
|
|
153
|
+
}
|
|
140
154
|
var _Prodigio = class _Prodigio {
|
|
141
155
|
constructor(config) {
|
|
142
156
|
// ── Jobs ──────────────────────────────────────────────────────────────────
|
|
@@ -180,9 +194,7 @@ var _Prodigio = class _Prodigio {
|
|
|
180
194
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
181
195
|
url.searchParams.set("key", this.apiKey);
|
|
182
196
|
if (params) {
|
|
183
|
-
for (const [k, v] of Object.entries(params))
|
|
184
|
-
if (v !== void 0) url.searchParams.set(k, v);
|
|
185
|
-
}
|
|
197
|
+
for (const [k, v] of Object.entries(params)) if (v !== void 0) url.searchParams.set(k, v);
|
|
186
198
|
}
|
|
187
199
|
const res = await fetch(url.toString());
|
|
188
200
|
if (!res.ok) {
|
|
@@ -217,75 +229,75 @@ var _Prodigio = class _Prodigio {
|
|
|
217
229
|
}
|
|
218
230
|
static badge(poweredBy) {
|
|
219
231
|
const pb = poweredBy != null ? poweredBy : _Prodigio.POWERED_BY;
|
|
220
|
-
return {
|
|
221
|
-
href: pb.url,
|
|
222
|
-
"data-prodigio-badge": "true",
|
|
223
|
-
target: "_blank",
|
|
224
|
-
rel: "noopener noreferrer",
|
|
225
|
-
text: pb.text
|
|
226
|
-
};
|
|
232
|
+
return { href: pb.url, "data-prodigio-badge": "true", target: "_blank", rel: "noopener noreferrer", text: pb.text };
|
|
227
233
|
}
|
|
228
234
|
static meta() {
|
|
229
235
|
return { name: "prodigio-badge", content: "true" };
|
|
230
236
|
}
|
|
231
|
-
// ──
|
|
237
|
+
// ── destroy() ─────────────────────────────────────────────────────────────
|
|
238
|
+
static destroy() {
|
|
239
|
+
removeBadge();
|
|
240
|
+
_initialized = false;
|
|
241
|
+
}
|
|
242
|
+
// ── init() ────────────────────────────────────────────────────────────────
|
|
232
243
|
static async init(config) {
|
|
233
244
|
var _a;
|
|
234
245
|
if (typeof window === "undefined") return;
|
|
246
|
+
if (_initialized) return;
|
|
247
|
+
_initialized = true;
|
|
235
248
|
const { key, badgeToken, baseUrl = DEFAULT_BASE_URL, badge: badgeConfig } = config;
|
|
236
249
|
const position = (_a = badgeConfig == null ? void 0 : badgeConfig.position) != null ? _a : "bottom-right";
|
|
237
|
-
const paths = badgeConfig == null ? void 0 : badgeConfig.paths;
|
|
238
|
-
if (paths && paths.length > 0) {
|
|
239
|
-
const currentPath = window.location.pathname;
|
|
240
|
-
if (!paths.some((p) => currentPath === p || currentPath.startsWith(p + "/"))) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
const hostname = window.location.hostname;
|
|
245
250
|
const cached = getCachedToken(key);
|
|
246
|
-
let bestToken = null;
|
|
247
|
-
let bestTokenRaw = null;
|
|
248
251
|
const [initClaims, cachedClaims] = await Promise.all([
|
|
249
252
|
badgeToken ? verifyBadgeToken(badgeToken) : Promise.resolve(null),
|
|
250
253
|
cached ? verifyBadgeToken(cached.token) : Promise.resolve(null)
|
|
251
254
|
]);
|
|
255
|
+
let bestToken = null;
|
|
252
256
|
if (initClaims && cachedClaims) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
} else {
|
|
257
|
-
bestToken = cachedClaims;
|
|
258
|
-
bestTokenRaw = cached.token;
|
|
259
|
-
}
|
|
260
|
-
} else if (initClaims) {
|
|
261
|
-
bestToken = initClaims;
|
|
262
|
-
bestTokenRaw = badgeToken;
|
|
263
|
-
} else if (cachedClaims) {
|
|
264
|
-
bestToken = cachedClaims;
|
|
265
|
-
bestTokenRaw = cached.token;
|
|
257
|
+
bestToken = new Date(initClaims.badgeExemptUntil) >= new Date(cachedClaims.badgeExemptUntil) ? initClaims : cachedClaims;
|
|
258
|
+
} else {
|
|
259
|
+
bestToken = initClaims != null ? initClaims : cachedClaims;
|
|
266
260
|
}
|
|
261
|
+
const hostname = window.location.hostname;
|
|
267
262
|
const domainAllowed = bestToken ? bestToken.allowedDomains.length === 0 || bestToken.allowedDomains.includes(hostname) : true;
|
|
268
263
|
const isExempt = bestToken !== null && !bestToken.badgeRequired && domainAllowed;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const cacheAge = Date.now() - cached.cachedAt;
|
|
273
|
-
if (cacheAge < GRACE_PERIOD_MS) {
|
|
264
|
+
let careersPath = null;
|
|
265
|
+
function evaluateBadge() {
|
|
266
|
+
if (isExempt) {
|
|
274
267
|
removeBadge();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (careersPath) {
|
|
271
|
+
if (pathMatches(window.location.pathname, careersPath)) {
|
|
272
|
+
injectBadge(position);
|
|
273
|
+
} else {
|
|
274
|
+
removeBadge();
|
|
275
|
+
}
|
|
275
276
|
} else {
|
|
277
|
+
if (!bestToken && cached) {
|
|
278
|
+
const cacheAge = Date.now() - cached.cachedAt;
|
|
279
|
+
if (cacheAge < GRACE_PERIOD_MS) {
|
|
280
|
+
removeBadge();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
276
284
|
injectBadge(position);
|
|
277
285
|
}
|
|
278
|
-
} else {
|
|
279
|
-
injectBadge(position);
|
|
280
286
|
}
|
|
287
|
+
evaluateBadge();
|
|
288
|
+
installRouteWatcher();
|
|
289
|
+
_routeChangeCallbacks.push(evaluateBadge);
|
|
281
290
|
setTimeout(async () => {
|
|
282
291
|
var _a2, _b;
|
|
283
292
|
try {
|
|
284
293
|
const res = await fetch(`${baseUrl}/api/sdk/config?key=${encodeURIComponent(key)}`);
|
|
285
294
|
if (!res.ok) return;
|
|
286
295
|
const data = await res.json();
|
|
296
|
+
if (data.careersPath !== void 0) {
|
|
297
|
+
careersPath = data.careersPath;
|
|
298
|
+
}
|
|
287
299
|
if (data.badgeRequired) {
|
|
288
|
-
|
|
300
|
+
evaluateBadge();
|
|
289
301
|
return;
|
|
290
302
|
}
|
|
291
303
|
if (data.badgeToken) {
|
|
@@ -295,12 +307,13 @@ var _Prodigio = class _Prodigio {
|
|
|
295
307
|
removeBadge();
|
|
296
308
|
}
|
|
297
309
|
}
|
|
310
|
+
evaluateBadge();
|
|
298
311
|
} catch {
|
|
299
312
|
}
|
|
300
313
|
}, 0);
|
|
301
314
|
}
|
|
302
315
|
};
|
|
303
|
-
// ── Badge
|
|
316
|
+
// ── Badge static helpers ──────────────────────────────────────────────────
|
|
304
317
|
_Prodigio.POWERED_BY = {
|
|
305
318
|
text: "Hiring powered by Prodigio",
|
|
306
319
|
url: "https://prodigio.io"
|