@hiofu/apply-sdk 0.1.5 → 0.1.6-beta.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/README.md +73 -87
- package/dist/{chunk-MFY3F4OY.js → chunk-7JEEWWEX.js} +37 -10
- package/dist/{client-Ct5xyQMk.d.cts → client-7yPni-fK.d.cts} +7 -6
- package/dist/{client-Ct5xyQMk.d.ts → client-7yPni-fK.d.ts} +7 -6
- package/dist/index.cjs +57 -15
- package/dist/index.d.cts +19 -7
- package/dist/index.d.ts +19 -7
- package/dist/index.global.js +1 -1
- package/dist/index.js +21 -6
- package/dist/react.cjs +65 -13
- package/dist/react.d.cts +5 -3
- package/dist/react.d.ts +5 -3
- package/dist/react.js +29 -4
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -18,50 +18,51 @@ npm install @hiofu/apply-sdk
|
|
|
18
18
|
|
|
19
19
|
## Quick Start
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
### React (simplest)
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { HiofuApplyButton } from "@hiofu/apply-sdk/react";
|
|
25
|
+
|
|
26
|
+
export function ApplyButton({ jobId, jobTitle }) {
|
|
27
|
+
return (
|
|
28
|
+
<HiofuApplyButton
|
|
29
|
+
clientId={process.env.NEXT_PUBLIC_HIOFU_KEY}
|
|
30
|
+
variant="primary"
|
|
31
|
+
options={{ jobId, jobTitle }}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The SDK infers sandbox/production from the key prefix and uses the
|
|
38
|
+
HIOFU-hosted callback by default. No extra config needed.
|
|
39
|
+
|
|
40
|
+
### Vanilla JS
|
|
23
41
|
|
|
24
42
|
```ts
|
|
25
43
|
import { createApplyClient } from "@hiofu/apply-sdk";
|
|
26
44
|
|
|
27
45
|
const hiofu = createApplyClient({
|
|
28
|
-
environment: "sandbox",
|
|
29
46
|
publicKey: "pk_test_xxx",
|
|
30
|
-
redirectUri: "https://jobs.example.com/oauth/callback.html",
|
|
31
|
-
onComplete(result) {
|
|
32
|
-
console.log(result.application.id, result.application.status);
|
|
33
|
-
},
|
|
34
|
-
onError(error) {
|
|
35
|
-
console.error(error.code, error.correlationId, error.message);
|
|
36
|
-
},
|
|
37
47
|
});
|
|
38
48
|
|
|
39
49
|
const result = await hiofu.apply({
|
|
40
50
|
jobId: "job_123",
|
|
41
|
-
|
|
42
|
-
employerId: "emp_456",
|
|
43
|
-
employerName: "Acme Inc",
|
|
44
|
-
role: {
|
|
45
|
-
externalRoleId: "job_123",
|
|
46
|
-
externalEmployerId: "emp_456",
|
|
47
|
-
title: "Senior Engineer",
|
|
48
|
-
locations: ["London", "Remote"],
|
|
49
|
-
metadata: { department: "Engineering" },
|
|
50
|
-
},
|
|
51
|
+
role: { title: "Senior Engineer" },
|
|
51
52
|
idempotencyKey: "apply_attempt_01JXYZ...",
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
console.log(result.
|
|
55
|
-
console.log(result.snapshot?.trustBand);
|
|
55
|
+
console.log(result.applicationId);
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
## Configuration
|
|
59
59
|
|
|
60
|
-
`createApplyClient`
|
|
60
|
+
`createApplyClient` resolves the correct HIOFU URLs from the key prefix and
|
|
61
|
+
rejects key/environment mismatches before opening the popup.
|
|
61
62
|
|
|
62
|
-
- `environment` (required): `sandbox` or `production`.
|
|
63
63
|
- `publicKey` (required): Your publishable key, e.g. `pk_test_…` or `pk_live_…`.
|
|
64
|
-
- `
|
|
64
|
+
- `environment` (optional): Inferred from key prefix. Override with `"sandbox"` or `"production"` if needed.
|
|
65
|
+
- `redirectUri` (optional): Defaults to the HIOFU-hosted callback. Set this only if you host your own callback page.
|
|
65
66
|
- `storage` (default `memory`): Token storage, either `memory` (cleared on reload) or `session` (persists the access token for the browser session; refresh tokens are not persisted in browser storage).
|
|
66
67
|
- `scopes` / `applyScopes` (optional): Default scopes for `authorize()` / `apply()`.
|
|
67
68
|
- `popupOptions.timeoutMs` (default 300_000): Popup wait limit in milliseconds.
|
|
@@ -72,13 +73,15 @@ console.log(result.snapshot?.trustBand);
|
|
|
72
73
|
|
|
73
74
|
`HiofuClient` remains available as the lower-level compatibility API using `clientId`, `hiofuOrigin`, and `apiBase`.
|
|
74
75
|
|
|
75
|
-
##
|
|
76
|
+
## Optional Backend Setup Automation
|
|
76
77
|
|
|
77
78
|
If your team prefers automation over the HIOFU Developer settings UI,
|
|
78
79
|
the same setup actions are available from the management client.
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
The public browser Apply flow does not need an employer access token.
|
|
82
|
+
Use this management client only from your backend or internal tooling
|
|
83
|
+
when you want to automate setup. The access token should stay on trusted
|
|
84
|
+
infrastructure and must never be exposed to browser code.
|
|
82
85
|
|
|
83
86
|
```ts
|
|
84
87
|
import { createManagementClient } from "@hiofu/apply-sdk";
|
|
@@ -102,16 +105,11 @@ const role = await management.createRole({
|
|
|
102
105
|
await management.updateRoleStatus(role.id, "hiring");
|
|
103
106
|
```
|
|
104
107
|
|
|
105
|
-
### Issue the publishable key
|
|
108
|
+
### Issue the publishable key and save the route
|
|
106
109
|
|
|
107
110
|
```ts
|
|
108
111
|
await management.issuePublishableKey();
|
|
109
112
|
|
|
110
|
-
await management.addRedirectUri({
|
|
111
|
-
mode: "test",
|
|
112
|
-
uri: "https://jobs.example.com/oauth/callback-shim.html",
|
|
113
|
-
});
|
|
114
|
-
|
|
115
113
|
await management.saveRoleMapping({
|
|
116
114
|
mode: "test",
|
|
117
115
|
externalRoleId: "job_123",
|
|
@@ -119,6 +117,16 @@ await management.saveRoleMapping({
|
|
|
119
117
|
});
|
|
120
118
|
```
|
|
121
119
|
|
|
120
|
+
Register a callback URI only if you override the SDK's HIOFU-hosted callback
|
|
121
|
+
with your own `redirectUri`.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
await management.addRedirectUri({
|
|
125
|
+
mode: "test",
|
|
126
|
+
uri: "https://jobs.example.com/oauth/callback.html",
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
122
130
|
### Update or remove setup later
|
|
123
131
|
|
|
124
132
|
```ts
|
|
@@ -152,62 +160,41 @@ HIOFU Developer settings UI:
|
|
|
152
160
|
|
|
153
161
|
### Sandbox vs Production
|
|
154
162
|
|
|
155
|
-
Switch environments by key
|
|
156
|
-
opening the popup: `pk_test_*` must use sandbox URLs, and `pk_live_*` must use
|
|
157
|
-
production URLs.
|
|
163
|
+
Switch environments by key. The SDK infers the correct URLs from the prefix.
|
|
158
164
|
|
|
159
165
|
```ts
|
|
160
|
-
const isSandbox = process.env.NODE_ENV !== "production";
|
|
166
|
+
const isSandbox = process.env.NODE_ENV !== "production";
|
|
161
167
|
|
|
162
168
|
const hiofu = createApplyClient({
|
|
163
|
-
environment: isSandbox ? "sandbox" : "production",
|
|
164
169
|
publicKey: isSandbox ? "pk_test_xxx" : "pk_live_xxx",
|
|
165
|
-
redirectUri: `${window.location.origin}/oauth/callback.html`,
|
|
166
170
|
});
|
|
167
171
|
```
|
|
168
172
|
|
|
169
173
|
## React
|
|
170
174
|
|
|
175
|
+
### Standalone button (simplest)
|
|
176
|
+
|
|
171
177
|
```tsx
|
|
172
|
-
import { HiofuApplyButton
|
|
178
|
+
import { HiofuApplyButton } from "@hiofu/apply-sdk/react";
|
|
173
179
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
apiBase: "https://api.sandbox.hiofu.com/api",
|
|
181
|
-
redirectUri: "https://jobs.example.com/oauth/callback.html",
|
|
182
|
-
// Optional extras with sensible defaults
|
|
183
|
-
// storage: "session",
|
|
184
|
-
// applyScopes: ["applications.write", "passport.snapshot"],
|
|
185
|
-
// onEvent: (e) => console.debug("hiofu", e),
|
|
186
|
-
}}
|
|
187
|
-
>
|
|
188
|
-
<ApplyButton />
|
|
189
|
-
</HiofuProvider>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
180
|
+
<HiofuApplyButton
|
|
181
|
+
clientId="pk_test_xxx"
|
|
182
|
+
variant="primary"
|
|
183
|
+
options={{ jobId: "job_123", jobTitle: "Senior Engineer" }}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
192
186
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
externalEmployerId: "emp_456",
|
|
205
|
-
title: "Senior Engineer",
|
|
206
|
-
},
|
|
207
|
-
}}
|
|
208
|
-
/>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
187
|
+
No provider needed for a single button. The SDK infers everything from the key.
|
|
188
|
+
|
|
189
|
+
### With provider (multiple buttons sharing config)
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { HiofuApplyButton, HiofuProvider } from "@hiofu/apply-sdk/react";
|
|
193
|
+
|
|
194
|
+
<HiofuProvider config={{ clientId: "pk_test_xxx" }}>
|
|
195
|
+
<HiofuApplyButton options={{ jobId: "job_1", jobTitle: "Role A" }} />
|
|
196
|
+
<HiofuApplyButton options={{ jobId: "job_2", jobTitle: "Role B" }} />
|
|
197
|
+
</HiofuProvider>
|
|
211
198
|
```
|
|
212
199
|
|
|
213
200
|
`HiofuApplyButton` ships three variants: `primary`, `secondary`, and `ghost`.
|
|
@@ -257,19 +244,13 @@ function ApplyButton() {
|
|
|
257
244
|
<script
|
|
258
245
|
src="https://cdn.hiofu.com/apply-sdk.global.js"
|
|
259
246
|
data-client-id="pk_test_xxx"
|
|
260
|
-
data-hiofu-origin="https://sandbox.hiofu.com"
|
|
261
|
-
data-api-base="https://api.sandbox.hiofu.com/api"
|
|
262
|
-
data-redirect-uri="https://jobs.example.com/oauth/callback.html"
|
|
263
247
|
></script>
|
|
264
248
|
|
|
265
249
|
<button
|
|
266
250
|
data-hiofu-apply
|
|
267
251
|
data-job-id="job_123"
|
|
268
252
|
data-job-title="Senior Engineer"
|
|
269
|
-
data-employer-id="emp_456"
|
|
270
253
|
data-employer-name="Acme Inc"
|
|
271
|
-
data-external-role-id="job_123"
|
|
272
|
-
data-external-employer-id="emp_456"
|
|
273
254
|
data-role-department="Engineering"
|
|
274
255
|
data-role-locations="London,Remote"
|
|
275
256
|
>
|
|
@@ -321,9 +302,15 @@ await hiofu.apply({
|
|
|
321
302
|
});
|
|
322
303
|
```
|
|
323
304
|
|
|
324
|
-
## Callback Handling
|
|
305
|
+
## Custom Callback Handling
|
|
306
|
+
|
|
307
|
+
Most integrations do not need a callback page. When `redirectUri` is omitted,
|
|
308
|
+
the SDK uses the HIOFU-hosted callback for the key's environment.
|
|
325
309
|
|
|
326
|
-
|
|
310
|
+
Only host your own callback when you have a specific same-origin requirement.
|
|
311
|
+
In that case, register the exact callback URL in HIOFU Developer settings and
|
|
312
|
+
pass it as `redirectUri`. Do not register callback URLs on domains you do not
|
|
313
|
+
control. The page should relay the OAuth result back to the opener:
|
|
327
314
|
|
|
328
315
|
```html
|
|
329
316
|
<!doctype html>
|
|
@@ -395,7 +382,7 @@ Returned payload highlights:
|
|
|
395
382
|
|
|
396
383
|
## Security Notes
|
|
397
384
|
|
|
398
|
-
-
|
|
385
|
+
- Prefer the HIOFU-hosted callback. If you host your own callback page, register only domains you control and pass the URL explicitly as `redirectUri`.
|
|
399
386
|
- Browser integrations receive a short-lived access token only through the SDK runtime. Refresh tokens are never exposed to your UI code.
|
|
400
387
|
- The SDK does not inject third-party fonts or global styles into your pages. Keep typography ownership inside your app shell.
|
|
401
388
|
- Do not log raw application payloads in production UIs.
|
|
@@ -452,7 +439,6 @@ import {
|
|
|
452
439
|
|
|
453
440
|
const hiofu = new HiofuClient({
|
|
454
441
|
clientId: "pk_live_xxx",
|
|
455
|
-
redirectUri: `${location.origin}/oauth/callback.html`,
|
|
456
442
|
});
|
|
457
443
|
|
|
458
444
|
try {
|
|
@@ -338,9 +338,6 @@ var HiofuPopupError = class extends Error {
|
|
|
338
338
|
function resolveRedirectUri(config, hiofuOrigin) {
|
|
339
339
|
if (config.redirectUri) return config.redirectUri;
|
|
340
340
|
const hiofuBaseOrigin = new URL(hiofuOrigin).origin;
|
|
341
|
-
if (typeof window !== "undefined" && window.location.origin && window.location.origin !== hiofuBaseOrigin) {
|
|
342
|
-
return new URL("/oauth/callback.html", window.location.origin).toString();
|
|
343
|
-
}
|
|
344
341
|
return `${hiofuBaseOrigin}/oauth/callback-shim`;
|
|
345
342
|
}
|
|
346
343
|
async function authorize(config, scopes, context, callbacks) {
|
|
@@ -354,6 +351,9 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
354
351
|
const url = new URL(`${hiofuOrigin}/oauth/consent`);
|
|
355
352
|
url.searchParams.set("client_id", config.clientId);
|
|
356
353
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
354
|
+
if (window.location?.origin) {
|
|
355
|
+
url.searchParams.set("opener_origin", window.location.origin);
|
|
356
|
+
}
|
|
357
357
|
url.searchParams.set("scope", scopes.join(" "));
|
|
358
358
|
url.searchParams.set("state", state);
|
|
359
359
|
url.searchParams.set("code_challenge", challenge);
|
|
@@ -389,6 +389,7 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
389
389
|
let channel = null;
|
|
390
390
|
let openerLostAttention = false;
|
|
391
391
|
let openerRegainedAttention = false;
|
|
392
|
+
let popupClosedAt = null;
|
|
392
393
|
const cleanup = () => {
|
|
393
394
|
settled = true;
|
|
394
395
|
window.removeEventListener("message", onMessage);
|
|
@@ -538,14 +539,28 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
538
539
|
}
|
|
539
540
|
} catch {
|
|
540
541
|
}
|
|
541
|
-
if (popup.closed
|
|
542
|
+
if (popup.closed) {
|
|
543
|
+
popupClosedAt ?? (popupClosedAt = Date.now());
|
|
544
|
+
} else {
|
|
545
|
+
popupClosedAt = null;
|
|
546
|
+
}
|
|
547
|
+
const canTreatAsClosed = popup.closed && popupClosedAt !== null && openerRegainedAttention && document.hasFocus() && Date.now() - popupClosedAt > 5e3;
|
|
548
|
+
if (canTreatAsClosed) {
|
|
542
549
|
try {
|
|
543
550
|
const raw = localStorage.getItem("hiofu_oauth_result");
|
|
544
|
-
if (raw)
|
|
545
|
-
handleResult(JSON.parse(raw), "close_check");
|
|
546
|
-
}
|
|
551
|
+
if (raw) handleResult(JSON.parse(raw), "close_check");
|
|
547
552
|
} catch {
|
|
548
553
|
}
|
|
554
|
+
if (!settled) {
|
|
555
|
+
cleanup();
|
|
556
|
+
callbacks?.onPopupClosed?.("user_closed");
|
|
557
|
+
reject(
|
|
558
|
+
new HiofuPopupError(
|
|
559
|
+
"user_closed",
|
|
560
|
+
"Authorization popup closed before HIOFU could complete the request. Please try again."
|
|
561
|
+
)
|
|
562
|
+
);
|
|
563
|
+
}
|
|
549
564
|
}
|
|
550
565
|
}, 500);
|
|
551
566
|
overallTimeout = window.setTimeout(() => {
|
|
@@ -699,10 +714,13 @@ var HiofuClient = class {
|
|
|
699
714
|
if (!config.clientId) {
|
|
700
715
|
throw new Error("HiofuClient: clientId is required");
|
|
701
716
|
}
|
|
717
|
+
const isSandboxKey = config.clientId.startsWith("pk_test_");
|
|
718
|
+
const defaultOrigin = isSandboxKey ? "https://sandbox.hiofu.com" : "https://hiofu.com";
|
|
719
|
+
const defaultApiBase = isSandboxKey ? "https://api.sandbox.hiofu.com/api" : "https://api.hiofu.com/api";
|
|
702
720
|
this.config = {
|
|
703
721
|
...config,
|
|
704
|
-
hiofuOrigin: config.hiofuOrigin ??
|
|
705
|
-
apiBase: config.apiBase ??
|
|
722
|
+
hiofuOrigin: config.hiofuOrigin ?? defaultOrigin,
|
|
723
|
+
apiBase: config.apiBase ?? defaultApiBase,
|
|
706
724
|
storage: config.storage ?? "memory",
|
|
707
725
|
authorizeTimeoutMs: config.authorizeTimeoutMs ?? 5 * 6e4
|
|
708
726
|
};
|
|
@@ -824,12 +842,21 @@ var HiofuClient = class {
|
|
|
824
842
|
idempotencyKey,
|
|
825
843
|
variationId: selectedVariationId
|
|
826
844
|
});
|
|
845
|
+
const resolvedRole = opts.role ? {
|
|
846
|
+
...opts.role,
|
|
847
|
+
externalRoleId: opts.role.externalRoleId || opts.jobId,
|
|
848
|
+
title: opts.role.title || opts.jobTitle,
|
|
849
|
+
externalEmployerId: opts.role.externalEmployerId || opts.employerId || void 0
|
|
850
|
+
} : {
|
|
851
|
+
externalRoleId: opts.jobId,
|
|
852
|
+
title: opts.jobTitle
|
|
853
|
+
};
|
|
827
854
|
const json = await submitApplication(this.config, access, {
|
|
828
855
|
jobId: opts.jobId,
|
|
829
856
|
jobTitle: opts.jobTitle,
|
|
830
857
|
employerId: opts.employerId,
|
|
831
858
|
employerName: opts.employerName,
|
|
832
|
-
role:
|
|
859
|
+
role: resolvedRole,
|
|
833
860
|
variationId: selectedVariationId ?? void 0,
|
|
834
861
|
idempotencyKey
|
|
835
862
|
});
|
|
@@ -11,8 +11,8 @@ interface HiofuConfig {
|
|
|
11
11
|
/** Optional default scopes for `apply()`. */
|
|
12
12
|
applyScopes?: HiofuScope[];
|
|
13
13
|
/** Where the popup will redirect on success. Must be one of the partner's
|
|
14
|
-
* registered URIs. If omitted
|
|
15
|
-
*
|
|
14
|
+
* registered URIs. If omitted, the SDK uses the HIOFU-hosted callback for
|
|
15
|
+
* the selected environment. */
|
|
16
16
|
redirectUri?: string;
|
|
17
17
|
/** Where to store the access token client-side. */
|
|
18
18
|
storage?: "session" | "memory";
|
|
@@ -26,11 +26,12 @@ interface HiofuTokenSet {
|
|
|
26
26
|
scopes: HiofuScope[];
|
|
27
27
|
}
|
|
28
28
|
interface HiofuApplyRole {
|
|
29
|
-
/** Partner-owned stable role/job identifier. */
|
|
30
|
-
externalRoleId
|
|
29
|
+
/** Partner-owned stable role/job identifier. Defaults to jobId when omitted. */
|
|
30
|
+
externalRoleId?: string;
|
|
31
31
|
/** Partner-owned stable employer/company identifier, optional for direct HIOFU-domain integrations. */
|
|
32
32
|
externalEmployerId?: string;
|
|
33
|
-
|
|
33
|
+
/** Defaults to jobTitle when omitted. */
|
|
34
|
+
title?: string;
|
|
34
35
|
description?: string;
|
|
35
36
|
department?: string;
|
|
36
37
|
locations?: string[];
|
|
@@ -424,4 +425,4 @@ declare class HiofuClient {
|
|
|
424
425
|
logout(): Promise<void>;
|
|
425
426
|
}
|
|
426
427
|
|
|
427
|
-
export { DEFAULT_APPLY_SCOPES as D,
|
|
428
|
+
export { DEFAULT_APPLY_SCOPES as D, type HiofuApplyOptions as H, DEFAULT_AUTHORIZE_SCOPES as a, type HiofuApplyResult as b, type HiofuApplyRole as c, HiofuClient as d, type HiofuConfig as e, type HiofuEvent as f, type HiofuManagementAddRedirectUriInput as g, type HiofuManagementConfig as h, type HiofuManagementCreateRoleInput as i, type HiofuManagementDeveloperSettings as j, type HiofuManagementEnvironment as k, type HiofuManagementEnvironmentMode as l, type HiofuManagementListRolesParams as m, type HiofuManagementPaginatedResult as n, type HiofuManagementRedirectUri as o, type HiofuManagementRole as p, type HiofuManagementRoleDimension as q, type HiofuManagementRoleDimensionSkill as r, type HiofuManagementRoleListItem as s, type HiofuManagementRoleMapping as t, type HiofuManagementRoleStatus as u, type HiofuManagementSaveRoleMappingInput as v, type HiofuManagementUpdateRoleInput as w, type HiofuPartner as x, type HiofuScope as y, type HiofuTokenSet as z };
|
|
@@ -11,8 +11,8 @@ interface HiofuConfig {
|
|
|
11
11
|
/** Optional default scopes for `apply()`. */
|
|
12
12
|
applyScopes?: HiofuScope[];
|
|
13
13
|
/** Where the popup will redirect on success. Must be one of the partner's
|
|
14
|
-
* registered URIs. If omitted
|
|
15
|
-
*
|
|
14
|
+
* registered URIs. If omitted, the SDK uses the HIOFU-hosted callback for
|
|
15
|
+
* the selected environment. */
|
|
16
16
|
redirectUri?: string;
|
|
17
17
|
/** Where to store the access token client-side. */
|
|
18
18
|
storage?: "session" | "memory";
|
|
@@ -26,11 +26,12 @@ interface HiofuTokenSet {
|
|
|
26
26
|
scopes: HiofuScope[];
|
|
27
27
|
}
|
|
28
28
|
interface HiofuApplyRole {
|
|
29
|
-
/** Partner-owned stable role/job identifier. */
|
|
30
|
-
externalRoleId
|
|
29
|
+
/** Partner-owned stable role/job identifier. Defaults to jobId when omitted. */
|
|
30
|
+
externalRoleId?: string;
|
|
31
31
|
/** Partner-owned stable employer/company identifier, optional for direct HIOFU-domain integrations. */
|
|
32
32
|
externalEmployerId?: string;
|
|
33
|
-
|
|
33
|
+
/** Defaults to jobTitle when omitted. */
|
|
34
|
+
title?: string;
|
|
34
35
|
description?: string;
|
|
35
36
|
department?: string;
|
|
36
37
|
locations?: string[];
|
|
@@ -424,4 +425,4 @@ declare class HiofuClient {
|
|
|
424
425
|
logout(): Promise<void>;
|
|
425
426
|
}
|
|
426
427
|
|
|
427
|
-
export { DEFAULT_APPLY_SCOPES as D,
|
|
428
|
+
export { DEFAULT_APPLY_SCOPES as D, type HiofuApplyOptions as H, DEFAULT_AUTHORIZE_SCOPES as a, type HiofuApplyResult as b, type HiofuApplyRole as c, HiofuClient as d, type HiofuConfig as e, type HiofuEvent as f, type HiofuManagementAddRedirectUriInput as g, type HiofuManagementConfig as h, type HiofuManagementCreateRoleInput as i, type HiofuManagementDeveloperSettings as j, type HiofuManagementEnvironment as k, type HiofuManagementEnvironmentMode as l, type HiofuManagementListRolesParams as m, type HiofuManagementPaginatedResult as n, type HiofuManagementRedirectUri as o, type HiofuManagementRole as p, type HiofuManagementRoleDimension as q, type HiofuManagementRoleDimensionSkill as r, type HiofuManagementRoleListItem as s, type HiofuManagementRoleMapping as t, type HiofuManagementRoleStatus as u, type HiofuManagementSaveRoleMappingInput as v, type HiofuManagementUpdateRoleInput as w, type HiofuPartner as x, type HiofuScope as y, type HiofuTokenSet as z };
|
package/dist/index.cjs
CHANGED
|
@@ -385,9 +385,6 @@ var HiofuPopupError = class extends Error {
|
|
|
385
385
|
function resolveRedirectUri(config, hiofuOrigin) {
|
|
386
386
|
if (config.redirectUri) return config.redirectUri;
|
|
387
387
|
const hiofuBaseOrigin = new URL(hiofuOrigin).origin;
|
|
388
|
-
if (typeof window !== "undefined" && window.location.origin && window.location.origin !== hiofuBaseOrigin) {
|
|
389
|
-
return new URL("/oauth/callback.html", window.location.origin).toString();
|
|
390
|
-
}
|
|
391
388
|
return `${hiofuBaseOrigin}/oauth/callback-shim`;
|
|
392
389
|
}
|
|
393
390
|
async function authorize(config, scopes, context, callbacks) {
|
|
@@ -401,6 +398,9 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
401
398
|
const url = new URL(`${hiofuOrigin}/oauth/consent`);
|
|
402
399
|
url.searchParams.set("client_id", config.clientId);
|
|
403
400
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
401
|
+
if (window.location?.origin) {
|
|
402
|
+
url.searchParams.set("opener_origin", window.location.origin);
|
|
403
|
+
}
|
|
404
404
|
url.searchParams.set("scope", scopes.join(" "));
|
|
405
405
|
url.searchParams.set("state", state);
|
|
406
406
|
url.searchParams.set("code_challenge", challenge);
|
|
@@ -436,6 +436,7 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
436
436
|
let channel = null;
|
|
437
437
|
let openerLostAttention = false;
|
|
438
438
|
let openerRegainedAttention = false;
|
|
439
|
+
let popupClosedAt = null;
|
|
439
440
|
const cleanup = () => {
|
|
440
441
|
settled = true;
|
|
441
442
|
window.removeEventListener("message", onMessage);
|
|
@@ -585,14 +586,28 @@ async function authorize(config, scopes, context, callbacks) {
|
|
|
585
586
|
}
|
|
586
587
|
} catch {
|
|
587
588
|
}
|
|
588
|
-
if (popup.closed
|
|
589
|
+
if (popup.closed) {
|
|
590
|
+
popupClosedAt ?? (popupClosedAt = Date.now());
|
|
591
|
+
} else {
|
|
592
|
+
popupClosedAt = null;
|
|
593
|
+
}
|
|
594
|
+
const canTreatAsClosed = popup.closed && popupClosedAt !== null && openerRegainedAttention && document.hasFocus() && Date.now() - popupClosedAt > 5e3;
|
|
595
|
+
if (canTreatAsClosed) {
|
|
589
596
|
try {
|
|
590
597
|
const raw = localStorage.getItem("hiofu_oauth_result");
|
|
591
|
-
if (raw)
|
|
592
|
-
handleResult(JSON.parse(raw), "close_check");
|
|
593
|
-
}
|
|
598
|
+
if (raw) handleResult(JSON.parse(raw), "close_check");
|
|
594
599
|
} catch {
|
|
595
600
|
}
|
|
601
|
+
if (!settled) {
|
|
602
|
+
cleanup();
|
|
603
|
+
callbacks?.onPopupClosed?.("user_closed");
|
|
604
|
+
reject(
|
|
605
|
+
new HiofuPopupError(
|
|
606
|
+
"user_closed",
|
|
607
|
+
"Authorization popup closed before HIOFU could complete the request. Please try again."
|
|
608
|
+
)
|
|
609
|
+
);
|
|
610
|
+
}
|
|
596
611
|
}
|
|
597
612
|
}, 500);
|
|
598
613
|
overallTimeout = window.setTimeout(() => {
|
|
@@ -746,10 +761,13 @@ var HiofuClient = class {
|
|
|
746
761
|
if (!config.clientId) {
|
|
747
762
|
throw new Error("HiofuClient: clientId is required");
|
|
748
763
|
}
|
|
764
|
+
const isSandboxKey = config.clientId.startsWith("pk_test_");
|
|
765
|
+
const defaultOrigin = isSandboxKey ? "https://sandbox.hiofu.com" : "https://hiofu.com";
|
|
766
|
+
const defaultApiBase = isSandboxKey ? "https://api.sandbox.hiofu.com/api" : "https://api.hiofu.com/api";
|
|
749
767
|
this.config = {
|
|
750
768
|
...config,
|
|
751
|
-
hiofuOrigin: config.hiofuOrigin ??
|
|
752
|
-
apiBase: config.apiBase ??
|
|
769
|
+
hiofuOrigin: config.hiofuOrigin ?? defaultOrigin,
|
|
770
|
+
apiBase: config.apiBase ?? defaultApiBase,
|
|
753
771
|
storage: config.storage ?? "memory",
|
|
754
772
|
authorizeTimeoutMs: config.authorizeTimeoutMs ?? 5 * 6e4
|
|
755
773
|
};
|
|
@@ -871,12 +889,21 @@ var HiofuClient = class {
|
|
|
871
889
|
idempotencyKey,
|
|
872
890
|
variationId: selectedVariationId
|
|
873
891
|
});
|
|
892
|
+
const resolvedRole = opts.role ? {
|
|
893
|
+
...opts.role,
|
|
894
|
+
externalRoleId: opts.role.externalRoleId || opts.jobId,
|
|
895
|
+
title: opts.role.title || opts.jobTitle,
|
|
896
|
+
externalEmployerId: opts.role.externalEmployerId || opts.employerId || void 0
|
|
897
|
+
} : {
|
|
898
|
+
externalRoleId: opts.jobId,
|
|
899
|
+
title: opts.jobTitle
|
|
900
|
+
};
|
|
874
901
|
const json = await submitApplication(this.config, access, {
|
|
875
902
|
jobId: opts.jobId,
|
|
876
903
|
jobTitle: opts.jobTitle,
|
|
877
904
|
employerId: opts.employerId,
|
|
878
905
|
employerName: opts.employerName,
|
|
879
|
-
role:
|
|
906
|
+
role: resolvedRole,
|
|
880
907
|
variationId: selectedVariationId ?? void 0,
|
|
881
908
|
idempotencyKey
|
|
882
909
|
});
|
|
@@ -1078,6 +1105,11 @@ var HiofuApplyError = class extends Error {
|
|
|
1078
1105
|
this.cause = args.cause;
|
|
1079
1106
|
}
|
|
1080
1107
|
};
|
|
1108
|
+
function inferEnvironment(publicKey) {
|
|
1109
|
+
if (publicKey.startsWith("pk_test_")) return "sandbox";
|
|
1110
|
+
if (publicKey.startsWith("pk_live_")) return "production";
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1081
1113
|
var ENDPOINTS = {
|
|
1082
1114
|
sandbox: {
|
|
1083
1115
|
hiofuOrigin: "https://sandbox.hiofu.com",
|
|
@@ -1110,15 +1142,24 @@ function assertPublicKey(environment, publicKey) {
|
|
|
1110
1142
|
}
|
|
1111
1143
|
}
|
|
1112
1144
|
function toApplyOptions(payload) {
|
|
1145
|
+
const jobId = payload.jobId ?? payload.externalJobId;
|
|
1146
|
+
if (!jobId) {
|
|
1147
|
+
throw new HiofuApplyError({
|
|
1148
|
+
code: "configuration_error",
|
|
1149
|
+
message: "HIOFU Apply requires a jobId.",
|
|
1150
|
+
correlationId: createCorrelationId(),
|
|
1151
|
+
retryable: false
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1113
1154
|
const locations = payload.role.locations ?? (payload.role.location ? [payload.role.location] : void 0);
|
|
1114
1155
|
const options = {
|
|
1115
|
-
jobId
|
|
1156
|
+
jobId,
|
|
1116
1157
|
jobTitle: payload.jobTitle ?? payload.role.title,
|
|
1117
1158
|
scopes: payload.scopes,
|
|
1118
1159
|
variationId: payload.variationId,
|
|
1119
1160
|
idempotencyKey: payload.idempotencyKey,
|
|
1120
1161
|
role: {
|
|
1121
|
-
externalRoleId:
|
|
1162
|
+
externalRoleId: jobId,
|
|
1122
1163
|
title: payload.role.title,
|
|
1123
1164
|
description: payload.role.description,
|
|
1124
1165
|
locations,
|
|
@@ -1203,8 +1244,9 @@ function toApplyError(error, correlationId) {
|
|
|
1203
1244
|
});
|
|
1204
1245
|
}
|
|
1205
1246
|
function createApplyClient(config) {
|
|
1206
|
-
|
|
1207
|
-
|
|
1247
|
+
const resolvedEnvironment = config.environment ?? inferEnvironment(config.publicKey) ?? "sandbox";
|
|
1248
|
+
assertPublicKey(resolvedEnvironment, config.publicKey);
|
|
1249
|
+
const endpoints = ENDPOINTS[resolvedEnvironment];
|
|
1208
1250
|
const client = new HiofuClient({
|
|
1209
1251
|
clientId: config.publicKey,
|
|
1210
1252
|
hiofuOrigin: config.hiofuOrigin ?? endpoints.hiofuOrigin,
|
|
@@ -1233,7 +1275,7 @@ function createApplyClient(config) {
|
|
|
1233
1275
|
const result = await client.apply(toApplyOptions(payload));
|
|
1234
1276
|
const normalized = toNormalizedResult(
|
|
1235
1277
|
result,
|
|
1236
|
-
|
|
1278
|
+
resolvedEnvironment,
|
|
1237
1279
|
payload.idempotencyKey
|
|
1238
1280
|
);
|
|
1239
1281
|
config.onComplete?.(normalized);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { D as DEFAULT_APPLY_SCOPES,
|
|
1
|
+
import { d as HiofuClient, y as HiofuScope, b as HiofuApplyResult, e as HiofuConfig, f as HiofuEvent, h as HiofuManagementConfig, m as HiofuManagementListRolesParams, n as HiofuManagementPaginatedResult, s as HiofuManagementRoleListItem, p as HiofuManagementRole, i as HiofuManagementCreateRoleInput, w as HiofuManagementUpdateRoleInput, u as HiofuManagementRoleStatus, j as HiofuManagementDeveloperSettings, v as HiofuManagementSaveRoleMappingInput, g as HiofuManagementAddRedirectUriInput, H as HiofuApplyOptions, z as HiofuTokenSet } from './client-7yPni-fK.cjs';
|
|
2
|
+
export { D as DEFAULT_APPLY_SCOPES, a as DEFAULT_AUTHORIZE_SCOPES, c as HiofuApplyRole, k as HiofuManagementEnvironment, l as HiofuManagementEnvironmentMode, o as HiofuManagementRedirectUri, q as HiofuManagementRoleDimension, r as HiofuManagementRoleDimensionSkill, t as HiofuManagementRoleMapping, x as HiofuPartner } from './client-7yPni-fK.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Scan the document for `[data-hiofu-apply]` buttons and wire them up to call
|
|
@@ -48,10 +48,12 @@ declare class HiofuApplyError extends Error {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
interface HiofuCreateApplyClientConfig {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
/** Inferred from publicKey prefix when omitted. */
|
|
52
|
+
environment?: HiofuEnvironment;
|
|
53
|
+
/** Publishable key: pk_test_* for sandbox, pk_live_* for production. */
|
|
53
54
|
publicKey: string;
|
|
54
|
-
|
|
55
|
+
/** Defaults to the HIOFU-hosted callback when omitted. */
|
|
56
|
+
redirectUri?: string;
|
|
55
57
|
scopes?: HiofuScope[];
|
|
56
58
|
applyScopes?: HiofuScope[];
|
|
57
59
|
storage?: HiofuConfig["storage"];
|
|
@@ -67,9 +69,12 @@ interface HiofuCreateApplyClientConfig {
|
|
|
67
69
|
/** Internal/testing override. Partners should use `environment`. */
|
|
68
70
|
apiBase?: string;
|
|
69
71
|
}
|
|
70
|
-
interface
|
|
72
|
+
interface HiofuApplyPayloadBase {
|
|
71
73
|
externalEmployerId?: string;
|
|
72
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Backwards-compatible alias for jobId. Prefer jobId in new integrations.
|
|
76
|
+
*/
|
|
77
|
+
externalJobId?: string;
|
|
73
78
|
role: {
|
|
74
79
|
title: string;
|
|
75
80
|
description?: string;
|
|
@@ -88,6 +93,13 @@ interface HiofuApplyPayload {
|
|
|
88
93
|
scopes?: HiofuScope[];
|
|
89
94
|
partnerTags?: Record<string, string>;
|
|
90
95
|
}
|
|
96
|
+
type HiofuApplyPayload = HiofuApplyPayloadBase & ({
|
|
97
|
+
jobId: string;
|
|
98
|
+
externalJobId?: string;
|
|
99
|
+
} | {
|
|
100
|
+
jobId?: string;
|
|
101
|
+
externalJobId: string;
|
|
102
|
+
});
|
|
91
103
|
interface HiofuNormalizedApplyResult {
|
|
92
104
|
applicationId: string;
|
|
93
105
|
partnerApplicationId?: string;
|