@cavuno/board 4.9.0 → 4.10.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/CHANGELOG.md +24 -0
- package/dist/{_spec-B9Ah8dNs.d.mts → _spec-BwUP7Wni.d.mts} +65 -1
- package/dist/{_spec-B9Ah8dNs.d.ts → _spec-BwUP7Wni.d.ts} +65 -1
- package/dist/{blog-BmqWfLZi.d.mts → blog-C_xXYOxc.d.mts} +1 -1
- package/dist/{blog-bh07fZ8Q.d.ts → blog-DC4BfQqF.d.ts} +1 -1
- package/dist/{board-B4jLqmxn.d.mts → board-CG8rDGTY.d.mts} +2 -2
- package/dist/{board-De8nLbk7.d.ts → board-zdQ875ck.d.ts} +2 -2
- package/dist/{breadcrumbs-BVQL2dNY.d.mts → breadcrumbs-BK7AqNp2.d.mts} +2 -2
- package/dist/{breadcrumbs-B1HVufC7.d.ts → breadcrumbs-qs9DC0yh.d.ts} +2 -2
- package/dist/browser/cavuno-board.global.min.js +1 -1
- package/dist/{chunk-T46JASKG.mjs → chunk-XEJWXRLK.mjs} +7 -0
- package/dist/filters.d.mts +2 -2
- package/dist/filters.d.ts +2 -2
- package/dist/format.d.mts +4 -4
- package/dist/format.d.ts +4 -4
- package/dist/index.d.mts +86 -14
- package/dist/index.d.ts +86 -14
- package/dist/index.js +118 -4
- package/dist/index.mjs +112 -5
- package/dist/{jobs-Iv6Wkvvf.d.ts → jobs-B-uO7ffG.d.ts} +1 -1
- package/dist/{jobs-B7q3BgIK.d.mts → jobs-BToqhRuU.d.mts} +1 -1
- package/dist/{search-DC0jatQN.d.mts → search-CvwKD0Va.d.mts} +1 -1
- package/dist/{search-CbDZwdyl.d.ts → search-Sl9-xi1z.d.ts} +1 -1
- package/dist/{seo-HCE7aCkh.d.mts → seo-B9b2AkSE.d.mts} +1 -1
- package/dist/{seo-BDFUuvXM.d.ts → seo-D1Vc_0HF.d.ts} +1 -1
- package/dist/seo-files.d.mts +2 -2
- package/dist/seo-files.d.ts +2 -2
- package/dist/seo.d.mts +6 -6
- package/dist/seo.d.ts +6 -6
- package/dist/server.d.mts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/server.mjs +1 -1
- package/dist/sitemap.d.mts +6 -6
- package/dist/sitemap.d.ts +6 -6
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/package.json +1 -1
- package/skills/cavuno-board-setup/SKILL.md +1 -0
- package/skills/cavuno-board-talent-access/SKILL.md +149 -0
- package/skills/manifest.json +8 -1
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isValidationError,
|
|
16
16
|
resolveStorage,
|
|
17
17
|
writeSession
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XEJWXRLK.mjs";
|
|
19
19
|
import {
|
|
20
20
|
paginate
|
|
21
21
|
} from "./chunk-DLSO6XXY.mjs";
|
|
@@ -39,7 +39,7 @@ function toSearchParams(query) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// src/version.ts
|
|
42
|
-
var SDK_VERSION = "4.
|
|
42
|
+
var SDK_VERSION = "4.10.0";
|
|
43
43
|
|
|
44
44
|
// src/client.ts
|
|
45
45
|
function isRawBody(body) {
|
|
@@ -1547,6 +1547,29 @@ function meNamespace(client) {
|
|
|
1547
1547
|
);
|
|
1548
1548
|
}
|
|
1549
1549
|
},
|
|
1550
|
+
/**
|
|
1551
|
+
* Stripe Customer Portal for a company I am an approved member of.
|
|
1552
|
+
* Surfaces every subscription on the company's Stripe customer (job
|
|
1553
|
+
* posting + talent access). Not a talent-access portal — candidate
|
|
1554
|
+
* `me.access.portal` is a different buyer.
|
|
1555
|
+
*/
|
|
1556
|
+
billingPortal: {
|
|
1557
|
+
/**
|
|
1558
|
+
* Mint a Stripe Customer Portal session. Optional `returnPath` is
|
|
1559
|
+
* resolved against the board origin.
|
|
1560
|
+
*
|
|
1561
|
+
* @example
|
|
1562
|
+
* const { url } = await board.me.companies.billingPortal.create('acme', {
|
|
1563
|
+
* returnPath: '/employers/billing',
|
|
1564
|
+
* });
|
|
1565
|
+
*/
|
|
1566
|
+
create(slug, body, options) {
|
|
1567
|
+
return client.fetch(
|
|
1568
|
+
`/me/companies/${encodeURIComponent(slug)}/billing-portal`,
|
|
1569
|
+
{ ...options, method: "POST", body }
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
},
|
|
1550
1573
|
/**
|
|
1551
1574
|
* The read-only reporting funnel that backs the hosted employer jobs
|
|
1552
1575
|
* table: per-job views / apply clicks / native applications,
|
|
@@ -1811,9 +1834,11 @@ function meNamespace(client) {
|
|
|
1811
1834
|
}
|
|
1812
1835
|
},
|
|
1813
1836
|
/**
|
|
1814
|
-
* The
|
|
1815
|
-
*
|
|
1816
|
-
* Candidates and unaffiliated viewers get
|
|
1837
|
+
* The employer talent-access paywall — "does this employer have
|
|
1838
|
+
* talent access?" plus remaining company-scoped unlock/message credits
|
|
1839
|
+
* and the charging model. Candidates and unaffiliated viewers get
|
|
1840
|
+
* `hasTalentAccess: false`. Message credits spend inline on
|
|
1841
|
+
* `conversations.start` (no separate spend endpoint).
|
|
1817
1842
|
*
|
|
1818
1843
|
* @example
|
|
1819
1844
|
* const { hasTalentAccess } = await board.me.talentAccess.retrieve();
|
|
@@ -1821,12 +1846,94 @@ function meNamespace(client) {
|
|
|
1821
1846
|
talentAccess: {
|
|
1822
1847
|
/**
|
|
1823
1848
|
* Retrieve the viewer's talent entitlement. Never cache — per-user.
|
|
1849
|
+
* Credits are company-scoped; `companyId` is set when the viewer has
|
|
1850
|
+
* exactly one approved membership, otherwise `null` (pass `companyId`
|
|
1851
|
+
* on writes — `company_required` with more than one).
|
|
1824
1852
|
*
|
|
1825
1853
|
* @example
|
|
1826
1854
|
* const access = await board.me.talentAccess.retrieve();
|
|
1827
1855
|
*/
|
|
1828
1856
|
retrieve(options) {
|
|
1829
1857
|
return client.fetch("/me/talent-access", options);
|
|
1858
|
+
},
|
|
1859
|
+
/**
|
|
1860
|
+
* Per-candidate unlock and credit state for the opaque `/p/{id}`
|
|
1861
|
+
* profile route. Named `/p/{handle}` is the share bypass.
|
|
1862
|
+
*
|
|
1863
|
+
* @example
|
|
1864
|
+
* const gate = await board.me.talentAccess.retrieveCandidate(candidateId);
|
|
1865
|
+
*/
|
|
1866
|
+
retrieveCandidate(candidateId, options) {
|
|
1867
|
+
return client.fetch(
|
|
1868
|
+
`/me/talent-access/candidates/${encodeURIComponent(candidateId)}`,
|
|
1869
|
+
options
|
|
1870
|
+
);
|
|
1871
|
+
},
|
|
1872
|
+
/**
|
|
1873
|
+
* Start embedded checkout for a public `talent_access` plan and return
|
|
1874
|
+
* a connected-account mount kit. Same shape as candidate-access
|
|
1875
|
+
* checkout; session metadata is `origin: talent_access`. `companyId`
|
|
1876
|
+
* is required when the viewer has more than one approved membership
|
|
1877
|
+
* (`company_required`).
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* const kit = await board.me.talentAccess.checkout({
|
|
1881
|
+
* planId,
|
|
1882
|
+
* returnPath: '/employers',
|
|
1883
|
+
* colorMode: 'light',
|
|
1884
|
+
* });
|
|
1885
|
+
*/
|
|
1886
|
+
checkout(body, options) {
|
|
1887
|
+
return client.fetch(
|
|
1888
|
+
"/me/talent-access/checkout",
|
|
1889
|
+
{ ...options, method: "POST", body }
|
|
1890
|
+
);
|
|
1891
|
+
},
|
|
1892
|
+
/**
|
|
1893
|
+
* Poll a talent-access checkout session: `open` (re-mountable via
|
|
1894
|
+
* `clientSecret`), `complete`, or `expired`. The session must be
|
|
1895
|
+
* `origin: talent_access` for this board user.
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* const s = await board.me.talentAccess.retrieveCheckout(kit.sessionId);
|
|
1899
|
+
*/
|
|
1900
|
+
retrieveCheckout(sessionId, options) {
|
|
1901
|
+
return client.fetch(
|
|
1902
|
+
`/me/talent-access/checkout/${encodeURIComponent(sessionId)}`,
|
|
1903
|
+
options
|
|
1904
|
+
);
|
|
1905
|
+
},
|
|
1906
|
+
/**
|
|
1907
|
+
* Spend one profile-unlock credit. Idempotent: already-unlocked
|
|
1908
|
+
* returns `{ alreadyUnlocked: true }` with no decrement. Credits are
|
|
1909
|
+
* company-scoped; `companyId` is required with multiple approved
|
|
1910
|
+
* memberships (`company_required`).
|
|
1911
|
+
*
|
|
1912
|
+
* @example
|
|
1913
|
+
* const unlock = await board.me.talentAccess.unlock({ candidateId });
|
|
1914
|
+
*/
|
|
1915
|
+
unlock(body, options) {
|
|
1916
|
+
return client.fetch("/me/talent-access/unlocks", {
|
|
1917
|
+
...options,
|
|
1918
|
+
method: "POST",
|
|
1919
|
+
body
|
|
1920
|
+
});
|
|
1921
|
+
},
|
|
1922
|
+
/**
|
|
1923
|
+
* Swap the company's primary talent_access subscription to `planId`
|
|
1924
|
+
* in place (prorated). Never a second checkout — Checkout would mint
|
|
1925
|
+
* a parallel subscription. Requires an existing talent_access sub.
|
|
1926
|
+
* `companyId` is required with multiple approved memberships.
|
|
1927
|
+
*
|
|
1928
|
+
* @example
|
|
1929
|
+
* await board.me.talentAccess.upgrade({ planId });
|
|
1930
|
+
*/
|
|
1931
|
+
upgrade(body, options) {
|
|
1932
|
+
return client.fetch("/me/talent-access/upgrade", {
|
|
1933
|
+
...options,
|
|
1934
|
+
method: "POST",
|
|
1935
|
+
body
|
|
1936
|
+
});
|
|
1830
1937
|
}
|
|
1831
1938
|
},
|
|
1832
1939
|
/**
|
package/dist/seo-files.d.mts
CHANGED
package/dist/seo-files.d.ts
CHANGED
package/dist/seo.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-
|
|
2
|
-
import { e as JsonLdObject } from './breadcrumbs-
|
|
3
|
-
export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-
|
|
4
|
-
import './_spec-
|
|
5
|
-
import './board-
|
|
6
|
-
import './jobs-
|
|
1
|
+
import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-C_xXYOxc.mjs';
|
|
2
|
+
import { e as JsonLdObject } from './breadcrumbs-BK7AqNp2.mjs';
|
|
3
|
+
export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-BK7AqNp2.mjs';
|
|
4
|
+
import './_spec-BwUP7Wni.mjs';
|
|
5
|
+
import './board-CG8rDGTY.mjs';
|
|
6
|
+
import './jobs-BToqhRuU.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Blog structured data on the `@cavuno/board` wire types, transcribed from
|
package/dist/seo.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-
|
|
2
|
-
import { e as JsonLdObject } from './breadcrumbs-
|
|
3
|
-
export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-
|
|
4
|
-
import './_spec-
|
|
5
|
-
import './board-
|
|
6
|
-
import './jobs-
|
|
1
|
+
import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DC4BfQqF.js';
|
|
2
|
+
import { e as JsonLdObject } from './breadcrumbs-qs9DC0yh.js';
|
|
3
|
+
export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-qs9DC0yh.js';
|
|
4
|
+
import './_spec-BwUP7Wni.js';
|
|
5
|
+
import './board-zdQ875ck.js';
|
|
6
|
+
import './jobs-B-uO7ffG.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Blog structured data on the `@cavuno/board` wire types, transcribed from
|
package/dist/server.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './board-
|
|
5
|
-
import './jobs-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-BwUP7Wni.mjs';
|
|
3
|
+
import './search-CvwKD0Va.mjs';
|
|
4
|
+
import './board-CG8rDGTY.mjs';
|
|
5
|
+
import './jobs-BToqhRuU.mjs';
|
|
6
|
+
import './seo-B9b2AkSE.mjs';
|
|
7
|
+
import './blog-C_xXYOxc.mjs';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/server.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './board-
|
|
5
|
-
import './jobs-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-BwUP7Wni.js';
|
|
3
|
+
import './search-Sl9-xi1z.js';
|
|
4
|
+
import './board-zdQ875ck.js';
|
|
5
|
+
import './jobs-B-uO7ffG.js';
|
|
6
|
+
import './seo-D1Vc_0HF.js';
|
|
7
|
+
import './blog-DC4BfQqF.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/server.mjs
CHANGED
package/dist/sitemap.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './board-
|
|
5
|
-
import './jobs-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-BwUP7Wni.mjs';
|
|
3
|
+
import './search-CvwKD0Va.mjs';
|
|
4
|
+
import './board-CG8rDGTY.mjs';
|
|
5
|
+
import './jobs-BToqhRuU.mjs';
|
|
6
|
+
import './seo-B9b2AkSE.mjs';
|
|
7
|
+
import './blog-C_xXYOxc.mjs';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/sitemap.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './board-
|
|
5
|
-
import './jobs-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-BwUP7Wni.js';
|
|
3
|
+
import './search-Sl9-xi1z.js';
|
|
4
|
+
import './board-zdQ875ck.js';
|
|
5
|
+
import './jobs-B-uO7ffG.js';
|
|
6
|
+
import './seo-D1Vc_0HF.js';
|
|
7
|
+
import './blog-DC4BfQqF.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/suggest.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-
|
|
2
|
-
import './_spec-
|
|
1
|
+
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-CvwKD0Va.mjs';
|
|
2
|
+
import './_spec-BwUP7Wni.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@cavuno/board/suggest` — framework-agnostic headless search-suggest
|
package/dist/suggest.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-
|
|
2
|
-
import './_spec-
|
|
1
|
+
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-Sl9-xi1z.js';
|
|
2
|
+
import './_spec-BwUP7Wni.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@cavuno/board/suggest` — framework-agnostic headless search-suggest
|
package/package.json
CHANGED
|
@@ -64,6 +64,7 @@ Route each enabled capability to its focused skill:
|
|
|
64
64
|
| Saved jobs and applications | `cavuno-board-applications` |
|
|
65
65
|
| Messaging | `cavuno-board-messaging` |
|
|
66
66
|
| Candidate paywall | `cavuno-board-paywall` |
|
|
67
|
+
| Employer talent access | `cavuno-board-talent-access` |
|
|
67
68
|
| Public job posting | `cavuno-board-post-a-job` |
|
|
68
69
|
| Localized chrome | `cavuno-board-i18n` |
|
|
69
70
|
| Metadata and structured data | `cavuno-board-seo` |
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cavuno-board-talent-access
|
|
3
|
+
description: Employer talent-access paywall with @cavuno/board. Use for charging models, remaining credits, per-candidate unlock gates, embedded checkout, in-place upgrades, or the company billing portal.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Employer talent-access paywall
|
|
7
|
+
|
|
8
|
+
Operators sell access to the candidate directory: profile-unlock credits and/or first-message credits. Credits are company-scoped. This is a different buyer from the candidate job-access paywall (`board.me.access.*`, skill `cavuno-board-paywall`).
|
|
9
|
+
|
|
10
|
+
Two charging models (from `retrieve().accessModel`):
|
|
11
|
+
|
|
12
|
+
- `paid_messaging` — full profiles; a first cold message spends a message credit.
|
|
13
|
+
- `paid_unlocks_and_messaging` — directory cards redact; opaque `/p/{id}` requires an unlock credit; messaging stays credit-gated.
|
|
14
|
+
|
|
15
|
+
When no public `talent_access` plan exists, `accessModel` is `none` and the paywall is inert.
|
|
16
|
+
|
|
17
|
+
## Read the CTA and remaining credits
|
|
18
|
+
|
|
19
|
+
`board.me.talentAccess.retrieve()` is the gating signal for a Message-vs-upsell CTA. Never cache it.
|
|
20
|
+
|
|
21
|
+
```ts snippet
|
|
22
|
+
const access = await board.me.talentAccess.retrieve();
|
|
23
|
+
access.hasTalentAccess;
|
|
24
|
+
access.accessModel;
|
|
25
|
+
access.unlockCreditsRemaining;
|
|
26
|
+
access.messageCreditsRemaining;
|
|
27
|
+
access.hasUnlimitedUnlocks;
|
|
28
|
+
access.hasUnlimitedMessages;
|
|
29
|
+
access.companyId;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`companyId` is set when the viewer has exactly one approved membership. It is `null` when they have none or more than one — pass `companyId` on writes or the API returns `company_required`.
|
|
33
|
+
|
|
34
|
+
## Gate one candidate
|
|
35
|
+
|
|
36
|
+
Per-candidate already-unlocked state is a sibling read so the singleton never takes a candidate id.
|
|
37
|
+
|
|
38
|
+
```ts snippet
|
|
39
|
+
const gate = await board.me.talentAccess.retrieveCandidate('bu_candidate');
|
|
40
|
+
if (!gate.alreadyUnlocked && !gate.hasUnlimitedUnlocks) {
|
|
41
|
+
renderUnlockCta(gate.unlockCreditsRemaining);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Mint and mount checkout
|
|
46
|
+
|
|
47
|
+
`checkout` requires a signed-in approved employer and returns a mount kit. `returnPath` is relative; session metadata is `origin: talent_access`. Public talent plans come from `board.plans.list({ purpose: 'talent_access' })`.
|
|
48
|
+
|
|
49
|
+
```ts snippet
|
|
50
|
+
import { loadStripe } from '@stripe/stripe-js';
|
|
51
|
+
|
|
52
|
+
const kit = await board.me.talentAccess.checkout({
|
|
53
|
+
planId: 'plan_1',
|
|
54
|
+
returnPath: '/employers',
|
|
55
|
+
colorMode: 'light',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const stripe = await loadStripe(kit.publishableKey, {
|
|
59
|
+
stripeAccount: kit.stripeAccountId,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The kit contains `sessionId`, `clientSecret`, `stripeAccountId`, `publishableKey`, and `offerType`. The host owns Stripe.js and embedded-checkout mounting. Gate failures use `talent_access_unavailable`, `company_required`, and `stripe_not_connected`; handle them with `cavuno-board-errors`.
|
|
64
|
+
|
|
65
|
+
## Confirm from remaining credits
|
|
66
|
+
|
|
67
|
+
`retrieveCheckout` reports `open`, `complete`, or `expired`. Open sessions are remountable with their `clientSecret`; expired sessions require a new checkout. After completion, poll `retrieve()` because webhook delivery is asynchronous.
|
|
68
|
+
|
|
69
|
+
```ts snippet
|
|
70
|
+
const checkout = await board.me.talentAccess.retrieveCheckout(kit.sessionId);
|
|
71
|
+
|
|
72
|
+
if (checkout.status === 'complete') {
|
|
73
|
+
let access = await board.me.talentAccess.retrieve();
|
|
74
|
+
for (let poll = 0; !access.hasTalentAccess && poll < 10; poll++) {
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
76
|
+
access = await board.me.talentAccess.retrieve();
|
|
77
|
+
}
|
|
78
|
+
if (access.hasTalentAccess) renderUnlockedDirectory();
|
|
79
|
+
else renderPendingAccess();
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Spend an unlock
|
|
84
|
+
|
|
85
|
+
Unlock is idempotent: a second call for the same company/candidate pair returns `alreadyUnlocked: true` with no decrement.
|
|
86
|
+
|
|
87
|
+
```ts snippet
|
|
88
|
+
const unlock = await board.me.talentAccess.unlock({
|
|
89
|
+
candidateId: 'bu_candidate',
|
|
90
|
+
});
|
|
91
|
+
if (unlock.alreadyUnlocked) renderProfile();
|
|
92
|
+
else renderProfile(unlock.unlockCreditsRemaining);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`talent_access_required` means no plan or no remaining unlock credits.
|
|
96
|
+
|
|
97
|
+
## Upgrade in place
|
|
98
|
+
|
|
99
|
+
Out-of-credits plan changes call `upgrade`, never a second checkout. Checkout would mint a parallel subscription.
|
|
100
|
+
|
|
101
|
+
```ts snippet
|
|
102
|
+
await board.me.talentAccess.upgrade({ planId: 'plan_pro' });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`already_on_plan` means the company already holds that plan. `talent_access_required` means there is no current talent_access subscription to swap.
|
|
106
|
+
|
|
107
|
+
## Open the company billing portal
|
|
108
|
+
|
|
109
|
+
Job-posting and talent-access subscriptions share one Stripe customer per company. There is no `me.talentAccess.portal`.
|
|
110
|
+
|
|
111
|
+
```ts snippet
|
|
112
|
+
const { url } = await board.me.companies.billingPortal.create('acme', {
|
|
113
|
+
returnPath: '/employers/billing',
|
|
114
|
+
});
|
|
115
|
+
location.href = url;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Message credits spend on start
|
|
119
|
+
|
|
120
|
+
There is no separate message-credit spend endpoint. The composer gates on `hasTalentAccess` and remaining message credits; `conversations.start` still 403s `messaging_talent_access_required` on a cold send without credit.
|
|
121
|
+
|
|
122
|
+
```ts snippet
|
|
123
|
+
await board.me.conversations.start({
|
|
124
|
+
candidateBoardUserId: 'bu_candidate',
|
|
125
|
+
body: 'Hi, your profile looks like a great fit.',
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Named vs opaque profile routes
|
|
130
|
+
|
|
131
|
+
Named `/p/{handle}` is the share bypass and always shows a full `public` profile. Opaque `/p/{id}` is the unlock-gated route. When `accessModel === 'paid_unlocks_and_messaging'`, directory cards redact for viewers who are not unlimited.
|
|
132
|
+
|
|
133
|
+
```ts snippet
|
|
134
|
+
const named = await board.talent.retrieve('jane-doe');
|
|
135
|
+
const opaque = await board.talent.retrieve('bu_candidate');
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Completion gate
|
|
139
|
+
|
|
140
|
+
- `retrieve()` drives the Message-vs-upsell CTA and remaining-credit hints.
|
|
141
|
+
- Opaque `/p/{id}` uses `retrieveCandidate` then `unlock`; named `/p/{handle}` does not.
|
|
142
|
+
- Checkout reaches `complete`, then bounded `retrieve()` polling reaches `hasTalentAccess: true`.
|
|
143
|
+
- `upgrade` is the out-of-credits plan swap; never a second checkout session.
|
|
144
|
+
- Billing management uses `me.companies.billingPortal.create`, not a talent-access portal.
|
|
145
|
+
- First-message spend stays on `conversations.start`.
|
|
146
|
+
|
|
147
|
+
## Cavuno SDK reference
|
|
148
|
+
|
|
149
|
+
For setup and API details beyond this workflow, use the [Cavuno Board SDK documentation](https://cavuno.com/docs/sdk).
|
package/skills/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.10.0",
|
|
3
3
|
"skills": [
|
|
4
4
|
{
|
|
5
5
|
"name": "cavuno-board-account",
|
|
@@ -154,6 +154,13 @@
|
|
|
154
154
|
"path": "skills/cavuno-board-smoke-test/SKILL.md",
|
|
155
155
|
"framework": null,
|
|
156
156
|
"category": "core"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "cavuno-board-talent-access",
|
|
160
|
+
"description": "Employer talent-access paywall with @cavuno/board. Use for charging models, remaining credits, per-candidate unlock gates, embedded checkout, in-place upgrades, or the company billing portal.",
|
|
161
|
+
"path": "skills/cavuno-board-talent-access/SKILL.md",
|
|
162
|
+
"framework": null,
|
|
163
|
+
"category": "core"
|
|
157
164
|
}
|
|
158
165
|
]
|
|
159
166
|
}
|