@cavuno/board 4.8.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/{_spec-DePC7a05.d.mts → _spec-BwUP7Wni.d.mts} +100 -1
  3. package/dist/{_spec-DePC7a05.d.ts → _spec-BwUP7Wni.d.ts} +100 -1
  4. package/dist/bin.mjs +174 -19
  5. package/dist/{blog-DbFr4VPW.d.mts → blog-C_xXYOxc.d.mts} +1 -1
  6. package/dist/{blog-ummlt6Uq.d.ts → blog-DC4BfQqF.d.ts} +1 -1
  7. package/dist/{board-zWyHbyi4.d.ts → board-CG8rDGTY.d.mts} +5 -3
  8. package/dist/{board-DxTMBgIf.d.mts → board-zdQ875ck.d.ts} +5 -3
  9. package/dist/{breadcrumbs-P4qh0zML.d.mts → breadcrumbs-BK7AqNp2.d.mts} +2 -2
  10. package/dist/{breadcrumbs-kbmspmfk.d.ts → breadcrumbs-qs9DC0yh.d.ts} +2 -2
  11. package/dist/browser/cavuno-board.global.min.js +1 -1
  12. package/dist/{chunk-IWWPHFK2.mjs → chunk-XEJWXRLK.mjs} +10 -0
  13. package/dist/doctor.d.mts +3 -1
  14. package/dist/doctor.d.ts +3 -1
  15. package/dist/doctor.js +169 -17
  16. package/dist/doctor.mjs +169 -17
  17. package/dist/filters.d.mts +2 -2
  18. package/dist/filters.d.ts +2 -2
  19. package/dist/format.d.mts +4 -4
  20. package/dist/format.d.ts +4 -4
  21. package/dist/index.d.mts +118 -24
  22. package/dist/index.d.ts +118 -24
  23. package/dist/index.js +127 -9
  24. package/dist/index.mjs +118 -10
  25. package/dist/{jobs-twt5TO9l.d.ts → jobs-B-uO7ffG.d.ts} +1 -1
  26. package/dist/{jobs-DTLDt57G.d.mts → jobs-BToqhRuU.d.mts} +1 -1
  27. package/dist/{search-f2UNlTfv.d.mts → search-CvwKD0Va.d.mts} +1 -1
  28. package/dist/{search-CHD6peIl.d.ts → search-Sl9-xi1z.d.ts} +1 -1
  29. package/dist/seo-B9b2AkSE.d.mts +12 -0
  30. package/dist/seo-D1Vc_0HF.d.ts +12 -0
  31. package/dist/seo-files.d.mts +36 -0
  32. package/dist/seo-files.d.ts +36 -0
  33. package/dist/seo-files.js +102 -0
  34. package/dist/seo-files.mjs +81 -0
  35. package/dist/seo.d.mts +6 -6
  36. package/dist/seo.d.ts +6 -6
  37. package/dist/server.d.mts +6 -5
  38. package/dist/server.d.ts +6 -5
  39. package/dist/server.mjs +1 -1
  40. package/dist/sitemap.d.mts +6 -5
  41. package/dist/sitemap.d.ts +6 -5
  42. package/dist/suggest.d.mts +2 -2
  43. package/dist/suggest.d.ts +2 -2
  44. package/package.json +11 -1
  45. package/skills/cavuno-board-account/SKILL.md +3 -1
  46. package/skills/cavuno-board-filters/SKILL.md +17 -3
  47. package/skills/cavuno-board-setup/SKILL.md +1 -0
  48. package/skills/cavuno-board-talent-access/SKILL.md +149 -0
  49. 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-IWWPHFK2.mjs";
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.8.0";
42
+ var SDK_VERSION = "4.10.0";
43
43
 
44
44
  // src/client.ts
45
45
  function isRawBody(body) {
@@ -818,9 +818,9 @@ function jobsNamespace(client) {
818
818
  );
819
819
  },
820
820
  /**
821
- * Create an opaque external-apply intent. A compatible starter then makes
822
- * its own board-local POST return a browser 303 to `gatewayUrl`; do not
823
- * render this value as a crawlable link. Pass
821
+ * Create an opaque external-apply intent. A compatible starter sends the
822
+ * candidate's browser to `gatewayUrl` (or asks it for the canonical JSON
823
+ * decision after a real Apply click); never render it as a crawlable link. Pass
824
824
  * `x-cavuno-board-capabilities: apply-gateway-v1` in `options.headers`;
825
825
  * legacy callers receive 404.
826
826
  */
@@ -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 viewer's talent entitlement on this board — "does this
1815
- * employer have talent access?" for gating a Message-vs-upsell CTA.
1816
- * Candidates and unaffiliated viewers get `hasTalentAccess: false`.
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
  /**
@@ -2804,10 +2911,11 @@ function createBoardClient(options) {
2804
2911
  client,
2805
2912
  /**
2806
2913
  * Board context — identity, brand (`logoUrl` + favicon `icons`), language,
2807
- * features, and analytics.
2914
+ * features, analytics, and AdSense (`ads.enabled` + `ads.clientId`).
2915
+ * Per-placement slot ids are not on this resource.
2808
2916
  *
2809
2917
  * @example
2810
- * const { name, language, logoUrl, icons } = await board.context();
2918
+ * const { name, language, logoUrl, icons, ads } = await board.context();
2811
2919
  */
2812
2920
  context(options2) {
2813
2921
  return client.fetch("", options2);
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DePC7a05.js';
1
+ import { S as Schemas } from './_spec-BwUP7Wni.js';
2
2
 
3
3
  /**
4
4
  * Optional pagination metadata returned by Board API list operations.
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DePC7a05.mjs';
1
+ import { S as Schemas } from './_spec-BwUP7Wni.mjs';
2
2
 
3
3
  /**
4
4
  * Optional pagination metadata returned by Board API list operations.
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DePC7a05.mjs';
1
+ import { S as Schemas } from './_spec-BwUP7Wni.mjs';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DePC7a05.js';
1
+ import { S as Schemas } from './_spec-BwUP7Wni.js';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -0,0 +1,12 @@
1
+ import { S as Schemas } from './_spec-BwUP7Wni.mjs';
2
+
3
+ /**
4
+ * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
5
+ * headless frontend rebuilds `robots.txt` / `ads.txt` / `indexnow-key.txt`
6
+ * (+ the Google site-verification `<meta>`) from, byte-identically to the
7
+ * hosted board. Icons and `themeColor` left in 4.0.0; applications
8
+ * own brand assets and presentation tokens.
9
+ */
10
+ type BoardSeo = Schemas['BoardSeo'];
11
+
12
+ export type { BoardSeo as B };
@@ -0,0 +1,12 @@
1
+ import { S as Schemas } from './_spec-BwUP7Wni.js';
2
+
3
+ /**
4
+ * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
5
+ * headless frontend rebuilds `robots.txt` / `ads.txt` / `indexnow-key.txt`
6
+ * (+ the Google site-verification `<meta>`) from, byte-identically to the
7
+ * hosted board. Icons and `themeColor` left in 4.0.0; applications
8
+ * own brand assets and presentation tokens.
9
+ */
10
+ type BoardSeo = Schemas['BoardSeo'];
11
+
12
+ export type { BoardSeo as B };
@@ -0,0 +1,36 @@
1
+ import { B as BoardSeo } from './seo-B9b2AkSE.mjs';
2
+ import './_spec-BwUP7Wni.mjs';
3
+
4
+ /**
5
+ * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
6
+ * (`robots.txt`, `ads.txt`, `indexnow-key.txt`) plus the Google
7
+ * site-verification meta descriptor.
8
+ *
9
+ * Pure, dependency-free: type-only import of `BoardSeo`. No node builtins,
10
+ * no framework packages. Hosted routes, the dispatch Worker, and the starter
11
+ * share these bytes so the files cannot drift.
12
+ */
13
+
14
+ declare const SEO_FILE_CONTENT_TYPE = "text/plain; charset=utf-8";
15
+ declare const ROBOTS_CACHE_CONTROL = "public, max-age=600, s-maxage=14400, stale-while-revalidate=86400";
16
+ declare const ADS_TXT_CACHE_CONTROL = "public, max-age=3600, must-revalidate";
17
+ declare const INDEXNOW_CACHE_CONTROL = "public, max-age=86400, must-revalidate";
18
+ type SeoFileResponseInit = {
19
+ method?: string;
20
+ };
21
+ /** Lines of the hosted robots body (no sitemap line). Exported so tests and hosted can share the literal. */
22
+ declare function robotsBody(input: {
23
+ canonicalBase: string;
24
+ sandbox?: boolean;
25
+ }): string;
26
+ declare function robotsResponse(seo: Pick<BoardSeo, 'canonicalBase'> & {
27
+ sandbox?: boolean;
28
+ }, init?: SeoFileResponseInit): Response;
29
+ declare function adsTxtResponse(seo: Pick<BoardSeo, 'adsTxt'>, init?: SeoFileResponseInit): Response;
30
+ declare function indexNowResponse(seo: Pick<BoardSeo, 'indexNowKey'>, init?: SeoFileResponseInit): Response;
31
+ declare function googleSiteVerificationMeta(token: string | null | undefined): {
32
+ name: 'google-site-verification';
33
+ content: string;
34
+ } | null;
35
+
36
+ export { ADS_TXT_CACHE_CONTROL, INDEXNOW_CACHE_CONTROL, ROBOTS_CACHE_CONTROL, SEO_FILE_CONTENT_TYPE, type SeoFileResponseInit, adsTxtResponse, googleSiteVerificationMeta, indexNowResponse, robotsBody, robotsResponse };
@@ -0,0 +1,36 @@
1
+ import { B as BoardSeo } from './seo-D1Vc_0HF.js';
2
+ import './_spec-BwUP7Wni.js';
3
+
4
+ /**
5
+ * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
6
+ * (`robots.txt`, `ads.txt`, `indexnow-key.txt`) plus the Google
7
+ * site-verification meta descriptor.
8
+ *
9
+ * Pure, dependency-free: type-only import of `BoardSeo`. No node builtins,
10
+ * no framework packages. Hosted routes, the dispatch Worker, and the starter
11
+ * share these bytes so the files cannot drift.
12
+ */
13
+
14
+ declare const SEO_FILE_CONTENT_TYPE = "text/plain; charset=utf-8";
15
+ declare const ROBOTS_CACHE_CONTROL = "public, max-age=600, s-maxage=14400, stale-while-revalidate=86400";
16
+ declare const ADS_TXT_CACHE_CONTROL = "public, max-age=3600, must-revalidate";
17
+ declare const INDEXNOW_CACHE_CONTROL = "public, max-age=86400, must-revalidate";
18
+ type SeoFileResponseInit = {
19
+ method?: string;
20
+ };
21
+ /** Lines of the hosted robots body (no sitemap line). Exported so tests and hosted can share the literal. */
22
+ declare function robotsBody(input: {
23
+ canonicalBase: string;
24
+ sandbox?: boolean;
25
+ }): string;
26
+ declare function robotsResponse(seo: Pick<BoardSeo, 'canonicalBase'> & {
27
+ sandbox?: boolean;
28
+ }, init?: SeoFileResponseInit): Response;
29
+ declare function adsTxtResponse(seo: Pick<BoardSeo, 'adsTxt'>, init?: SeoFileResponseInit): Response;
30
+ declare function indexNowResponse(seo: Pick<BoardSeo, 'indexNowKey'>, init?: SeoFileResponseInit): Response;
31
+ declare function googleSiteVerificationMeta(token: string | null | undefined): {
32
+ name: 'google-site-verification';
33
+ content: string;
34
+ } | null;
35
+
36
+ export { ADS_TXT_CACHE_CONTROL, INDEXNOW_CACHE_CONTROL, ROBOTS_CACHE_CONTROL, SEO_FILE_CONTENT_TYPE, type SeoFileResponseInit, adsTxtResponse, googleSiteVerificationMeta, indexNowResponse, robotsBody, robotsResponse };
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/seo-files/index.ts
21
+ var seo_files_exports = {};
22
+ __export(seo_files_exports, {
23
+ ADS_TXT_CACHE_CONTROL: () => ADS_TXT_CACHE_CONTROL,
24
+ INDEXNOW_CACHE_CONTROL: () => INDEXNOW_CACHE_CONTROL,
25
+ ROBOTS_CACHE_CONTROL: () => ROBOTS_CACHE_CONTROL,
26
+ SEO_FILE_CONTENT_TYPE: () => SEO_FILE_CONTENT_TYPE,
27
+ adsTxtResponse: () => adsTxtResponse,
28
+ googleSiteVerificationMeta: () => googleSiteVerificationMeta,
29
+ indexNowResponse: () => indexNowResponse,
30
+ robotsBody: () => robotsBody,
31
+ robotsResponse: () => robotsResponse
32
+ });
33
+ module.exports = __toCommonJS(seo_files_exports);
34
+ var SEO_FILE_CONTENT_TYPE = "text/plain; charset=utf-8";
35
+ var ROBOTS_CACHE_CONTROL = "public, max-age=600, s-maxage=14400, stale-while-revalidate=86400";
36
+ var ADS_TXT_CACHE_CONTROL = "public, max-age=3600, must-revalidate";
37
+ var INDEXNOW_CACHE_CONTROL = "public, max-age=86400, must-revalidate";
38
+ function robotsBody(input) {
39
+ if (input.sandbox) {
40
+ return ["User-Agent: *", "Disallow: /", ""].join("\n");
41
+ }
42
+ const canonicalBase = input.canonicalBase.replace(/\/+$/, "");
43
+ return [
44
+ "User-Agent: *",
45
+ "Allow: /",
46
+ "Disallow: /go/",
47
+ "Disallow: /t/",
48
+ "Disallow: /jobs?page=",
49
+ "Disallow: /jobs*&page=",
50
+ "Disallow: /jobs/*?page=",
51
+ "Disallow: /companies?page=",
52
+ "Disallow: /companies*&page=",
53
+ "Disallow: /companies/*?page=",
54
+ "Disallow: /talent?page=",
55
+ "Disallow: /talent*&page=",
56
+ "Disallow: /talent/*?page=",
57
+ "",
58
+ `Sitemap: ${canonicalBase}/sitemap.xml`,
59
+ ""
60
+ ].join("\n");
61
+ }
62
+ function robotsResponse(seo, init) {
63
+ return textFileResponse(
64
+ robotsBody({ canonicalBase: seo.canonicalBase, sandbox: seo.sandbox }),
65
+ ROBOTS_CACHE_CONTROL,
66
+ init
67
+ );
68
+ }
69
+ function adsTxtResponse(seo, init) {
70
+ return optionalTextFileResponse(seo.adsTxt, ADS_TXT_CACHE_CONTROL, init);
71
+ }
72
+ function indexNowResponse(seo, init) {
73
+ return optionalTextFileResponse(
74
+ seo.indexNowKey,
75
+ INDEXNOW_CACHE_CONTROL,
76
+ init
77
+ );
78
+ }
79
+ function googleSiteVerificationMeta(token) {
80
+ if (typeof token !== "string") return null;
81
+ const content = token.trim();
82
+ if (!content) return null;
83
+ return { name: "google-site-verification", content };
84
+ }
85
+ function isHead(init) {
86
+ return init?.method?.toUpperCase() === "HEAD";
87
+ }
88
+ function textFileResponse(body, cacheControl, init) {
89
+ return new Response(isHead(init) ? null : body, {
90
+ status: 200,
91
+ headers: {
92
+ "Content-Type": SEO_FILE_CONTENT_TYPE,
93
+ "Cache-Control": cacheControl
94
+ }
95
+ });
96
+ }
97
+ function optionalTextFileResponse(value, cacheControl, init) {
98
+ if (value == null || value === "") {
99
+ return new Response(null, { status: 404 });
100
+ }
101
+ return textFileResponse(value, cacheControl, init);
102
+ }
@@ -0,0 +1,81 @@
1
+ // src/seo-files/index.ts
2
+ var SEO_FILE_CONTENT_TYPE = "text/plain; charset=utf-8";
3
+ var ROBOTS_CACHE_CONTROL = "public, max-age=600, s-maxage=14400, stale-while-revalidate=86400";
4
+ var ADS_TXT_CACHE_CONTROL = "public, max-age=3600, must-revalidate";
5
+ var INDEXNOW_CACHE_CONTROL = "public, max-age=86400, must-revalidate";
6
+ function robotsBody(input) {
7
+ if (input.sandbox) {
8
+ return ["User-Agent: *", "Disallow: /", ""].join("\n");
9
+ }
10
+ const canonicalBase = input.canonicalBase.replace(/\/+$/, "");
11
+ return [
12
+ "User-Agent: *",
13
+ "Allow: /",
14
+ "Disallow: /go/",
15
+ "Disallow: /t/",
16
+ "Disallow: /jobs?page=",
17
+ "Disallow: /jobs*&page=",
18
+ "Disallow: /jobs/*?page=",
19
+ "Disallow: /companies?page=",
20
+ "Disallow: /companies*&page=",
21
+ "Disallow: /companies/*?page=",
22
+ "Disallow: /talent?page=",
23
+ "Disallow: /talent*&page=",
24
+ "Disallow: /talent/*?page=",
25
+ "",
26
+ `Sitemap: ${canonicalBase}/sitemap.xml`,
27
+ ""
28
+ ].join("\n");
29
+ }
30
+ function robotsResponse(seo, init) {
31
+ return textFileResponse(
32
+ robotsBody({ canonicalBase: seo.canonicalBase, sandbox: seo.sandbox }),
33
+ ROBOTS_CACHE_CONTROL,
34
+ init
35
+ );
36
+ }
37
+ function adsTxtResponse(seo, init) {
38
+ return optionalTextFileResponse(seo.adsTxt, ADS_TXT_CACHE_CONTROL, init);
39
+ }
40
+ function indexNowResponse(seo, init) {
41
+ return optionalTextFileResponse(
42
+ seo.indexNowKey,
43
+ INDEXNOW_CACHE_CONTROL,
44
+ init
45
+ );
46
+ }
47
+ function googleSiteVerificationMeta(token) {
48
+ if (typeof token !== "string") return null;
49
+ const content = token.trim();
50
+ if (!content) return null;
51
+ return { name: "google-site-verification", content };
52
+ }
53
+ function isHead(init) {
54
+ return init?.method?.toUpperCase() === "HEAD";
55
+ }
56
+ function textFileResponse(body, cacheControl, init) {
57
+ return new Response(isHead(init) ? null : body, {
58
+ status: 200,
59
+ headers: {
60
+ "Content-Type": SEO_FILE_CONTENT_TYPE,
61
+ "Cache-Control": cacheControl
62
+ }
63
+ });
64
+ }
65
+ function optionalTextFileResponse(value, cacheControl, init) {
66
+ if (value == null || value === "") {
67
+ return new Response(null, { status: 404 });
68
+ }
69
+ return textFileResponse(value, cacheControl, init);
70
+ }
71
+ export {
72
+ ADS_TXT_CACHE_CONTROL,
73
+ INDEXNOW_CACHE_CONTROL,
74
+ ROBOTS_CACHE_CONTROL,
75
+ SEO_FILE_CONTENT_TYPE,
76
+ adsTxtResponse,
77
+ googleSiteVerificationMeta,
78
+ indexNowResponse,
79
+ robotsBody,
80
+ robotsResponse
81
+ };
package/dist/seo.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DbFr4VPW.mjs';
2
- import { e as JsonLdObject } from './breadcrumbs-P4qh0zML.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-P4qh0zML.mjs';
4
- import './_spec-DePC7a05.mjs';
5
- import './board-DxTMBgIf.mjs';
6
- import './jobs-DTLDt57G.mjs';
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-ummlt6Uq.js';
2
- import { e as JsonLdObject } from './breadcrumbs-kbmspmfk.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-kbmspmfk.js';
4
- import './_spec-DePC7a05.js';
5
- import './board-zWyHbyi4.js';
6
- import './jobs-twt5TO9l.js';
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,9 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-DePC7a05.mjs';
3
- import './search-f2UNlTfv.mjs';
4
- import './board-DxTMBgIf.mjs';
5
- import './jobs-DTLDt57G.mjs';
6
- import './blog-DbFr4VPW.mjs';
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';
7
8
 
8
9
  /**
9
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './_spec-DePC7a05.js';
3
- import './search-CHD6peIl.js';
4
- import './board-zWyHbyi4.js';
5
- import './jobs-twt5TO9l.js';
6
- import './blog-ummlt6Uq.js';
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';
7
8
 
8
9
  /**
9
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  isNoStore,
3
3
  isUnauthorized,
4
4
  scopeToken
5
- } from "./chunk-IWWPHFK2.mjs";
5
+ } from "./chunk-XEJWXRLK.mjs";
6
6
 
7
7
  // src/server/cookie.ts
8
8
  var COOKIE_ATTRIBUTES = "Path=/; HttpOnly; Secure; SameSite=Lax";
@@ -1,9 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-DePC7a05.mjs';
3
- import './search-f2UNlTfv.mjs';
4
- import './board-DxTMBgIf.mjs';
5
- import './jobs-DTLDt57G.mjs';
6
- import './blog-DbFr4VPW.mjs';
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';
7
8
 
8
9
  /**
9
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './_spec-DePC7a05.js';
3
- import './search-CHD6peIl.js';
4
- import './board-zWyHbyi4.js';
5
- import './jobs-twt5TO9l.js';
6
- import './blog-ummlt6Uq.js';
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';
7
8
 
8
9
  /**
9
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
@@ -1,5 +1,5 @@
1
- import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-f2UNlTfv.mjs';
2
- import './_spec-DePC7a05.mjs';
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-CHD6peIl.js';
2
- import './_spec-DePC7a05.js';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "4.8.0",
3
+ "version": "4.10.0",
4
4
  "description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -154,6 +154,16 @@
154
154
  "default": "./dist/well-known.js"
155
155
  }
156
156
  },
157
+ "./seo-files": {
158
+ "import": {
159
+ "types": "./dist/seo-files.d.mts",
160
+ "default": "./dist/seo-files.mjs"
161
+ },
162
+ "require": {
163
+ "types": "./dist/seo-files.d.ts",
164
+ "default": "./dist/seo-files.js"
165
+ }
166
+ },
157
167
  "./server": {
158
168
  "import": {
159
169
  "types": "./dist/server.d.mts",