@prodigio-io/sdk 2.0.1 → 2.1.1
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.js +84 -68
- package/dist/index.mjs +84 -68
- package/package.json +1 -1
- package/dist/index.d.mts +0 -125
- package/dist/index.d.ts +0 -125
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,78 @@ 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;
|
|
274
|
+
if (process.env.NODE_ENV !== "production" && !document.querySelector('meta[name="prodigio-badge"]')) {
|
|
275
|
+
console.warn('[Prodigio] Missing <meta name="prodigio-badge" content="true"> in your page <head>. This is required for compliance detection. See docs.prodigio.io');
|
|
276
|
+
}
|
|
261
277
|
const { key, badgeToken, baseUrl = DEFAULT_BASE_URL, badge: badgeConfig } = config;
|
|
262
278
|
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
279
|
const cached = getCachedToken(key);
|
|
272
|
-
let bestToken = null;
|
|
273
|
-
let bestTokenRaw = null;
|
|
274
280
|
const [initClaims, cachedClaims] = await Promise.all([
|
|
275
281
|
badgeToken ? verifyBadgeToken(badgeToken) : Promise.resolve(null),
|
|
276
282
|
cached ? verifyBadgeToken(cached.token) : Promise.resolve(null)
|
|
277
283
|
]);
|
|
284
|
+
let bestToken = null;
|
|
278
285
|
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;
|
|
286
|
+
bestToken = new Date(initClaims.badgeExemptUntil) >= new Date(cachedClaims.badgeExemptUntil) ? initClaims : cachedClaims;
|
|
287
|
+
} else {
|
|
288
|
+
bestToken = initClaims != null ? initClaims : cachedClaims;
|
|
292
289
|
}
|
|
290
|
+
const hostname = window.location.hostname;
|
|
293
291
|
const domainAllowed = bestToken ? bestToken.allowedDomains.length === 0 || bestToken.allowedDomains.includes(hostname) : true;
|
|
294
292
|
const isExempt = bestToken !== null && !bestToken.badgeRequired && domainAllowed;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const cacheAge = Date.now() - cached.cachedAt;
|
|
299
|
-
if (cacheAge < GRACE_PERIOD_MS) {
|
|
293
|
+
let careersPath = null;
|
|
294
|
+
function evaluateBadge() {
|
|
295
|
+
if (isExempt) {
|
|
300
296
|
removeBadge();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (careersPath) {
|
|
300
|
+
if (pathMatches(window.location.pathname, careersPath)) {
|
|
301
|
+
injectBadge(position);
|
|
302
|
+
} else {
|
|
303
|
+
removeBadge();
|
|
304
|
+
}
|
|
301
305
|
} else {
|
|
306
|
+
if (!bestToken && cached) {
|
|
307
|
+
const cacheAge = Date.now() - cached.cachedAt;
|
|
308
|
+
if (cacheAge < GRACE_PERIOD_MS) {
|
|
309
|
+
removeBadge();
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
302
313
|
injectBadge(position);
|
|
303
314
|
}
|
|
304
|
-
} else {
|
|
305
|
-
injectBadge(position);
|
|
306
315
|
}
|
|
316
|
+
evaluateBadge();
|
|
317
|
+
installRouteWatcher();
|
|
318
|
+
_routeChangeCallbacks.push(evaluateBadge);
|
|
307
319
|
setTimeout(async () => {
|
|
308
320
|
var _a2, _b;
|
|
309
321
|
try {
|
|
310
322
|
const res = await fetch(`${baseUrl}/api/sdk/config?key=${encodeURIComponent(key)}`);
|
|
311
323
|
if (!res.ok) return;
|
|
312
324
|
const data = await res.json();
|
|
325
|
+
if (data.careersPath !== void 0) {
|
|
326
|
+
careersPath = data.careersPath;
|
|
327
|
+
}
|
|
313
328
|
if (data.badgeRequired) {
|
|
314
|
-
|
|
329
|
+
evaluateBadge();
|
|
315
330
|
return;
|
|
316
331
|
}
|
|
317
332
|
if (data.badgeToken) {
|
|
@@ -321,12 +336,13 @@ var _Prodigio = class _Prodigio {
|
|
|
321
336
|
removeBadge();
|
|
322
337
|
}
|
|
323
338
|
}
|
|
339
|
+
evaluateBadge();
|
|
324
340
|
} catch {
|
|
325
341
|
}
|
|
326
342
|
}, 0);
|
|
327
343
|
}
|
|
328
344
|
};
|
|
329
|
-
// ── Badge
|
|
345
|
+
// ── Badge static helpers ──────────────────────────────────────────────────
|
|
330
346
|
_Prodigio.POWERED_BY = {
|
|
331
347
|
text: "Hiring powered by Prodigio",
|
|
332
348
|
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,78 @@ 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;
|
|
248
|
+
if (process.env.NODE_ENV !== "production" && !document.querySelector('meta[name="prodigio-badge"]')) {
|
|
249
|
+
console.warn('[Prodigio] Missing <meta name="prodigio-badge" content="true"> in your page <head>. This is required for compliance detection. See docs.prodigio.io');
|
|
250
|
+
}
|
|
235
251
|
const { key, badgeToken, baseUrl = DEFAULT_BASE_URL, badge: badgeConfig } = config;
|
|
236
252
|
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
253
|
const cached = getCachedToken(key);
|
|
246
|
-
let bestToken = null;
|
|
247
|
-
let bestTokenRaw = null;
|
|
248
254
|
const [initClaims, cachedClaims] = await Promise.all([
|
|
249
255
|
badgeToken ? verifyBadgeToken(badgeToken) : Promise.resolve(null),
|
|
250
256
|
cached ? verifyBadgeToken(cached.token) : Promise.resolve(null)
|
|
251
257
|
]);
|
|
258
|
+
let bestToken = null;
|
|
252
259
|
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;
|
|
260
|
+
bestToken = new Date(initClaims.badgeExemptUntil) >= new Date(cachedClaims.badgeExemptUntil) ? initClaims : cachedClaims;
|
|
261
|
+
} else {
|
|
262
|
+
bestToken = initClaims != null ? initClaims : cachedClaims;
|
|
266
263
|
}
|
|
264
|
+
const hostname = window.location.hostname;
|
|
267
265
|
const domainAllowed = bestToken ? bestToken.allowedDomains.length === 0 || bestToken.allowedDomains.includes(hostname) : true;
|
|
268
266
|
const isExempt = bestToken !== null && !bestToken.badgeRequired && domainAllowed;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const cacheAge = Date.now() - cached.cachedAt;
|
|
273
|
-
if (cacheAge < GRACE_PERIOD_MS) {
|
|
267
|
+
let careersPath = null;
|
|
268
|
+
function evaluateBadge() {
|
|
269
|
+
if (isExempt) {
|
|
274
270
|
removeBadge();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (careersPath) {
|
|
274
|
+
if (pathMatches(window.location.pathname, careersPath)) {
|
|
275
|
+
injectBadge(position);
|
|
276
|
+
} else {
|
|
277
|
+
removeBadge();
|
|
278
|
+
}
|
|
275
279
|
} else {
|
|
280
|
+
if (!bestToken && cached) {
|
|
281
|
+
const cacheAge = Date.now() - cached.cachedAt;
|
|
282
|
+
if (cacheAge < GRACE_PERIOD_MS) {
|
|
283
|
+
removeBadge();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
276
287
|
injectBadge(position);
|
|
277
288
|
}
|
|
278
|
-
} else {
|
|
279
|
-
injectBadge(position);
|
|
280
289
|
}
|
|
290
|
+
evaluateBadge();
|
|
291
|
+
installRouteWatcher();
|
|
292
|
+
_routeChangeCallbacks.push(evaluateBadge);
|
|
281
293
|
setTimeout(async () => {
|
|
282
294
|
var _a2, _b;
|
|
283
295
|
try {
|
|
284
296
|
const res = await fetch(`${baseUrl}/api/sdk/config?key=${encodeURIComponent(key)}`);
|
|
285
297
|
if (!res.ok) return;
|
|
286
298
|
const data = await res.json();
|
|
299
|
+
if (data.careersPath !== void 0) {
|
|
300
|
+
careersPath = data.careersPath;
|
|
301
|
+
}
|
|
287
302
|
if (data.badgeRequired) {
|
|
288
|
-
|
|
303
|
+
evaluateBadge();
|
|
289
304
|
return;
|
|
290
305
|
}
|
|
291
306
|
if (data.badgeToken) {
|
|
@@ -295,12 +310,13 @@ var _Prodigio = class _Prodigio {
|
|
|
295
310
|
removeBadge();
|
|
296
311
|
}
|
|
297
312
|
}
|
|
313
|
+
evaluateBadge();
|
|
298
314
|
} catch {
|
|
299
315
|
}
|
|
300
316
|
}, 0);
|
|
301
317
|
}
|
|
302
318
|
};
|
|
303
|
-
// ── Badge
|
|
319
|
+
// ── Badge static helpers ──────────────────────────────────────────────────
|
|
304
320
|
_Prodigio.POWERED_BY = {
|
|
305
321
|
text: "Hiring powered by Prodigio",
|
|
306
322
|
url: "https://prodigio.io"
|
package/package.json
CHANGED
package/dist/index.d.mts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
interface ProdigioConfig {
|
|
2
|
-
apiKey: string;
|
|
3
|
-
baseUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
interface ProdigioInitConfig {
|
|
6
|
-
key: string;
|
|
7
|
-
badgeToken?: string;
|
|
8
|
-
baseUrl?: string;
|
|
9
|
-
badge?: {
|
|
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
|
-
};
|
|
15
|
-
}
|
|
16
|
-
interface SalaryRange {
|
|
17
|
-
min: number;
|
|
18
|
-
max: number;
|
|
19
|
-
currency: string;
|
|
20
|
-
period: 'monthly' | 'yearly';
|
|
21
|
-
}
|
|
22
|
-
interface PoweredBy {
|
|
23
|
-
text: string;
|
|
24
|
-
url: string;
|
|
25
|
-
}
|
|
26
|
-
interface Job {
|
|
27
|
-
id: string;
|
|
28
|
-
title: string;
|
|
29
|
-
companyName: string;
|
|
30
|
-
department: string;
|
|
31
|
-
location: string;
|
|
32
|
-
type: 'full-time' | 'part-time' | 'contract';
|
|
33
|
-
status: 'active' | 'closed' | 'archived' | 'draft';
|
|
34
|
-
description: string;
|
|
35
|
-
requirements: string;
|
|
36
|
-
eligibilityCriteria?: string;
|
|
37
|
-
salaryRange: SalaryRange | null;
|
|
38
|
-
applicationDeadline: string | null;
|
|
39
|
-
/** ISO 8601 date string e.g. "2026-04-01T09:00:00.000Z" — use new Date(createdAt) to convert */
|
|
40
|
-
createdAt: string;
|
|
41
|
-
/** ISO 8601 date string e.g. "2026-04-01T09:00:00.000Z" — use new Date(updatedAt) to convert */
|
|
42
|
-
updatedAt: string;
|
|
43
|
-
poweredBy: PoweredBy;
|
|
44
|
-
}
|
|
45
|
-
interface Applicant {
|
|
46
|
-
fullName: string;
|
|
47
|
-
email: string;
|
|
48
|
-
phone: string;
|
|
49
|
-
location?: string;
|
|
50
|
-
linkedin?: string;
|
|
51
|
-
}
|
|
52
|
-
interface CVInfo {
|
|
53
|
-
url: string;
|
|
54
|
-
fileName: string;
|
|
55
|
-
fileSize: number;
|
|
56
|
-
mimeType: string;
|
|
57
|
-
path?: string;
|
|
58
|
-
}
|
|
59
|
-
interface Achievement {
|
|
60
|
-
description: string;
|
|
61
|
-
attachment?: UploadResult | null;
|
|
62
|
-
}
|
|
63
|
-
interface SubmitApplicationParams {
|
|
64
|
-
jobId: string;
|
|
65
|
-
applicant: Applicant;
|
|
66
|
-
cv: CVInfo;
|
|
67
|
-
coverLetter?: string;
|
|
68
|
-
achievements?: Achievement[];
|
|
69
|
-
}
|
|
70
|
-
interface ApplicationResult {
|
|
71
|
-
id: string;
|
|
72
|
-
message: string;
|
|
73
|
-
scoringError: string | null;
|
|
74
|
-
}
|
|
75
|
-
interface UploadResult {
|
|
76
|
-
url: string;
|
|
77
|
-
fileName: string;
|
|
78
|
-
fileSize: number;
|
|
79
|
-
mimeType: string;
|
|
80
|
-
path: string;
|
|
81
|
-
}
|
|
82
|
-
interface ListJobsParams {
|
|
83
|
-
status?: 'active' | 'all';
|
|
84
|
-
department?: string;
|
|
85
|
-
}
|
|
86
|
-
interface BadgeProps {
|
|
87
|
-
href: string;
|
|
88
|
-
'data-prodigio-badge': string;
|
|
89
|
-
target: string;
|
|
90
|
-
rel: string;
|
|
91
|
-
text: string;
|
|
92
|
-
}
|
|
93
|
-
declare class ProdigioError extends Error {
|
|
94
|
-
readonly status: number;
|
|
95
|
-
readonly code?: string | undefined;
|
|
96
|
-
constructor(message: string, status: number, code?: string | undefined);
|
|
97
|
-
}
|
|
98
|
-
declare class Prodigio {
|
|
99
|
-
private readonly apiKey;
|
|
100
|
-
private readonly baseUrl;
|
|
101
|
-
constructor(config: ProdigioConfig | string);
|
|
102
|
-
private get;
|
|
103
|
-
private post;
|
|
104
|
-
private postForm;
|
|
105
|
-
readonly jobs: {
|
|
106
|
-
list: (params?: ListJobsParams) => Promise<Job[]>;
|
|
107
|
-
get: (jobId: string) => Promise<Job>;
|
|
108
|
-
};
|
|
109
|
-
readonly upload: {
|
|
110
|
-
cv: (file: File | Blob, fileName?: string) => Promise<UploadResult>;
|
|
111
|
-
achievement: (file: File | Blob, fileName?: string) => Promise<UploadResult>;
|
|
112
|
-
};
|
|
113
|
-
readonly applications: {
|
|
114
|
-
submit: (params: SubmitApplicationParams) => Promise<ApplicationResult>;
|
|
115
|
-
};
|
|
116
|
-
static readonly POWERED_BY: PoweredBy;
|
|
117
|
-
static badge(poweredBy?: PoweredBy): BadgeProps;
|
|
118
|
-
static meta(): {
|
|
119
|
-
name: string;
|
|
120
|
-
content: string;
|
|
121
|
-
};
|
|
122
|
-
static init(config: ProdigioInitConfig): Promise<void>;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export { type Achievement, type Applicant, type ApplicationResult, type BadgeProps, type CVInfo, type Job, type ListJobsParams, type PoweredBy, Prodigio, type ProdigioConfig, ProdigioError, type ProdigioInitConfig, type SalaryRange, type SubmitApplicationParams, type UploadResult, Prodigio as default };
|
package/dist/index.d.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
interface ProdigioConfig {
|
|
2
|
-
apiKey: string;
|
|
3
|
-
baseUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
interface ProdigioInitConfig {
|
|
6
|
-
key: string;
|
|
7
|
-
badgeToken?: string;
|
|
8
|
-
baseUrl?: string;
|
|
9
|
-
badge?: {
|
|
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
|
-
};
|
|
15
|
-
}
|
|
16
|
-
interface SalaryRange {
|
|
17
|
-
min: number;
|
|
18
|
-
max: number;
|
|
19
|
-
currency: string;
|
|
20
|
-
period: 'monthly' | 'yearly';
|
|
21
|
-
}
|
|
22
|
-
interface PoweredBy {
|
|
23
|
-
text: string;
|
|
24
|
-
url: string;
|
|
25
|
-
}
|
|
26
|
-
interface Job {
|
|
27
|
-
id: string;
|
|
28
|
-
title: string;
|
|
29
|
-
companyName: string;
|
|
30
|
-
department: string;
|
|
31
|
-
location: string;
|
|
32
|
-
type: 'full-time' | 'part-time' | 'contract';
|
|
33
|
-
status: 'active' | 'closed' | 'archived' | 'draft';
|
|
34
|
-
description: string;
|
|
35
|
-
requirements: string;
|
|
36
|
-
eligibilityCriteria?: string;
|
|
37
|
-
salaryRange: SalaryRange | null;
|
|
38
|
-
applicationDeadline: string | null;
|
|
39
|
-
/** ISO 8601 date string e.g. "2026-04-01T09:00:00.000Z" — use new Date(createdAt) to convert */
|
|
40
|
-
createdAt: string;
|
|
41
|
-
/** ISO 8601 date string e.g. "2026-04-01T09:00:00.000Z" — use new Date(updatedAt) to convert */
|
|
42
|
-
updatedAt: string;
|
|
43
|
-
poweredBy: PoweredBy;
|
|
44
|
-
}
|
|
45
|
-
interface Applicant {
|
|
46
|
-
fullName: string;
|
|
47
|
-
email: string;
|
|
48
|
-
phone: string;
|
|
49
|
-
location?: string;
|
|
50
|
-
linkedin?: string;
|
|
51
|
-
}
|
|
52
|
-
interface CVInfo {
|
|
53
|
-
url: string;
|
|
54
|
-
fileName: string;
|
|
55
|
-
fileSize: number;
|
|
56
|
-
mimeType: string;
|
|
57
|
-
path?: string;
|
|
58
|
-
}
|
|
59
|
-
interface Achievement {
|
|
60
|
-
description: string;
|
|
61
|
-
attachment?: UploadResult | null;
|
|
62
|
-
}
|
|
63
|
-
interface SubmitApplicationParams {
|
|
64
|
-
jobId: string;
|
|
65
|
-
applicant: Applicant;
|
|
66
|
-
cv: CVInfo;
|
|
67
|
-
coverLetter?: string;
|
|
68
|
-
achievements?: Achievement[];
|
|
69
|
-
}
|
|
70
|
-
interface ApplicationResult {
|
|
71
|
-
id: string;
|
|
72
|
-
message: string;
|
|
73
|
-
scoringError: string | null;
|
|
74
|
-
}
|
|
75
|
-
interface UploadResult {
|
|
76
|
-
url: string;
|
|
77
|
-
fileName: string;
|
|
78
|
-
fileSize: number;
|
|
79
|
-
mimeType: string;
|
|
80
|
-
path: string;
|
|
81
|
-
}
|
|
82
|
-
interface ListJobsParams {
|
|
83
|
-
status?: 'active' | 'all';
|
|
84
|
-
department?: string;
|
|
85
|
-
}
|
|
86
|
-
interface BadgeProps {
|
|
87
|
-
href: string;
|
|
88
|
-
'data-prodigio-badge': string;
|
|
89
|
-
target: string;
|
|
90
|
-
rel: string;
|
|
91
|
-
text: string;
|
|
92
|
-
}
|
|
93
|
-
declare class ProdigioError extends Error {
|
|
94
|
-
readonly status: number;
|
|
95
|
-
readonly code?: string | undefined;
|
|
96
|
-
constructor(message: string, status: number, code?: string | undefined);
|
|
97
|
-
}
|
|
98
|
-
declare class Prodigio {
|
|
99
|
-
private readonly apiKey;
|
|
100
|
-
private readonly baseUrl;
|
|
101
|
-
constructor(config: ProdigioConfig | string);
|
|
102
|
-
private get;
|
|
103
|
-
private post;
|
|
104
|
-
private postForm;
|
|
105
|
-
readonly jobs: {
|
|
106
|
-
list: (params?: ListJobsParams) => Promise<Job[]>;
|
|
107
|
-
get: (jobId: string) => Promise<Job>;
|
|
108
|
-
};
|
|
109
|
-
readonly upload: {
|
|
110
|
-
cv: (file: File | Blob, fileName?: string) => Promise<UploadResult>;
|
|
111
|
-
achievement: (file: File | Blob, fileName?: string) => Promise<UploadResult>;
|
|
112
|
-
};
|
|
113
|
-
readonly applications: {
|
|
114
|
-
submit: (params: SubmitApplicationParams) => Promise<ApplicationResult>;
|
|
115
|
-
};
|
|
116
|
-
static readonly POWERED_BY: PoweredBy;
|
|
117
|
-
static badge(poweredBy?: PoweredBy): BadgeProps;
|
|
118
|
-
static meta(): {
|
|
119
|
-
name: string;
|
|
120
|
-
content: string;
|
|
121
|
-
};
|
|
122
|
-
static init(config: ProdigioInitConfig): Promise<void>;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export { type Achievement, type Applicant, type ApplicationResult, type BadgeProps, type CVInfo, type Job, type ListJobsParams, type PoweredBy, Prodigio, type ProdigioConfig, ProdigioError, type ProdigioInitConfig, type SalaryRange, type SubmitApplicationParams, type UploadResult, Prodigio as default };
|