@cavuno/board 4.47.0 → 4.49.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 (63) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +19 -0
  3. package/dist/{_spec-DHa5r3B0.d.mts → _spec-DiQvT7IN.d.mts} +53 -3
  4. package/dist/{_spec-DHa5r3B0.d.ts → _spec-DiQvT7IN.d.ts} +53 -3
  5. package/dist/bin.mjs +1 -0
  6. package/dist/{blog-wxhB8zAH.d.ts → blog-BqUwoJRF.d.ts} +1 -1
  7. package/dist/{blog-DylAbc0L.d.mts → blog-DGa6Wk08.d.mts} +1 -1
  8. package/dist/{board-DHsd92Gy.d.ts → board-BNJ5Bsx2.d.ts} +2 -2
  9. package/dist/{board-Bpze3b50.d.mts → board-DM-vktAo.d.mts} +2 -2
  10. package/dist/{breadcrumbs-B6yhrHJV.d.mts → breadcrumbs-2A7uGl7p.d.mts} +5 -3
  11. package/dist/{breadcrumbs-15j5xvmN.d.ts → breadcrumbs-BBwMLBGL.d.ts} +5 -3
  12. package/dist/browser/cavuno-board.global.min.js +1 -1
  13. package/dist/{chunk-5KCWHENV.mjs → chunk-2KD2CWFL.mjs} +1 -1
  14. package/dist/{chunk-XXQCESMU.mjs → chunk-JFDWTTOQ.mjs} +5 -0
  15. package/dist/{chunk-KDFKVWTZ.mjs → chunk-JTFUOGWE.mjs} +3 -3
  16. package/dist/doctor.js +1 -0
  17. package/dist/doctor.mjs +1 -0
  18. package/dist/filters.d.mts +2 -2
  19. package/dist/filters.d.ts +2 -2
  20. package/dist/format.d.mts +4 -4
  21. package/dist/format.d.ts +4 -4
  22. package/dist/format.js +3 -2
  23. package/dist/format.mjs +2 -2
  24. package/dist/go.js +1 -0
  25. package/dist/go.mjs +1 -1
  26. package/dist/index.d.mts +75 -14
  27. package/dist/index.d.ts +75 -14
  28. package/dist/index.js +15 -4
  29. package/dist/index.mjs +15 -4
  30. package/dist/{jobs-CMK-DZg3.d.mts → jobs-DQZEGLIC.d.ts} +24 -2
  31. package/dist/{jobs-CIrTcMjw.d.ts → jobs-DsO3htwV.d.mts} +24 -2
  32. package/dist/paths.d.mts +7 -1
  33. package/dist/paths.d.ts +7 -1
  34. package/dist/paths.js +5 -0
  35. package/dist/paths.mjs +3 -1
  36. package/dist/route-contract.js +1 -0
  37. package/dist/route-contract.mjs +2 -2
  38. package/dist/{search-666oDd7H.d.ts → search-C3DpF31i.d.ts} +1 -1
  39. package/dist/{search-DBQApXN1.d.mts → search-g3oH9aPu.d.mts} +1 -1
  40. package/dist/{seo-ynqiQmby.d.ts → seo-BOPoZApt.d.ts} +1 -1
  41. package/dist/{seo-gY8y9RMw.d.mts → seo-DMpAStWc.d.mts} +1 -1
  42. package/dist/seo-files.d.mts +2 -2
  43. package/dist/seo-files.d.ts +2 -2
  44. package/dist/seo.d.mts +6 -6
  45. package/dist/seo.d.ts +6 -6
  46. package/dist/seo.js +3 -2
  47. package/dist/seo.mjs +2 -2
  48. package/dist/server.d.mts +6 -6
  49. package/dist/server.d.ts +6 -6
  50. package/dist/sitemap.d.mts +6 -6
  51. package/dist/sitemap.d.ts +6 -6
  52. package/dist/sitemap.js +1 -0
  53. package/dist/sitemap.mjs +1 -1
  54. package/dist/suggest.d.mts +2 -2
  55. package/dist/suggest.d.ts +2 -2
  56. package/dist/well-known.js +1 -0
  57. package/dist/well-known.mjs +2 -2
  58. package/package.json +1 -1
  59. package/skills/cavuno-board-job-alerts/SKILL.md +27 -1
  60. package/skills/cavuno-board-jobs/SKILL.md +33 -3
  61. package/skills/cavuno-board-setup/SKILL.md +13 -0
  62. package/skills/cavuno-board-talent-access/SKILL.md +2 -0
  63. package/skills/manifest.json +1 -1
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DHa5r3B0.js';
1
+ import { S as Schemas } from './_spec-DiQvT7IN.mjs';
2
2
 
3
3
  /**
4
4
  * Optional pagination metadata returned by Board API list operations.
@@ -114,6 +114,14 @@ type JobsListQuery = {
114
114
  * jobs in the place itself. Ignored for region and country places.
115
115
  */
116
116
  radius?: number;
117
+ /**
118
+ * With `location` and no `radius`: widen a city or locality to the market
119
+ * default distance (25 mi in the US, GB, LR and MM; 50 km elsewhere),
120
+ * computed from the resolved place. Regions and countries are not
121
+ * widened; an explicit `radius` wins. Saves resolving the place first to
122
+ * pick the radius.
123
+ */
124
+ defaultRadius?: boolean;
117
125
  /** Category slug seed (the `/jobs/[keyword]` page) — server resolves it to the English source name; unresolvable → 404. */
118
126
  category?: string;
119
127
  /** Skill slug seed (the `/jobs/skills/[skill]` page) — server-resolved; unresolvable → 404. */
@@ -121,6 +129,20 @@ type JobsListQuery = {
121
129
  /** Sparse fieldset (Medusa-style `+field`). Only `'+description'` is supported — adds `description` to each card. */
122
130
  fields?: string;
123
131
  };
132
+ /**
133
+ * An opt-in capability token for `jobs.retrieve`. `apply-gateway-v1` selects
134
+ * the country-gated Apply shape (opaque Sponsored Apply).
135
+ */
136
+ type JobCapability = 'apply-gateway-v1';
137
+ type JobRetrieveQuery = {
138
+ /**
139
+ * Capability opt-ins, sent as the `capabilities` query parameter. Same
140
+ * effect as the `x-cavuno-board-capabilities` header, but the response
141
+ * stays shared-cacheable under its own URL; the header form is never
142
+ * cached.
143
+ */
144
+ capabilities?: JobCapability[];
145
+ };
124
146
  type JobsSimilarQuery = {
125
147
  /** How many similar jobs to return (1–20; default 5). */
126
148
  limit?: number;
@@ -143,4 +165,4 @@ type ObjectReferenceFilter = {
143
165
  */
144
166
  type JobsSearchBody = Schemas['PublicSearchJobsBody'];
145
167
 
146
- export type { CustomFieldValues as C, EmploymentType as E, JobSort as J, ListEnvelope as L, ObjectReferenceFilter as O, PublicJob as P, RemoteOption as R, Seniority as S, CustomFieldFilter as a, JobCollectionChoiceQuery as b, JobsListQuery as c, JobCardListEnvelope as d, JobsSearchBody as e, JobCardSearchEnvelope as f, JobsSimilarQuery as g, SearchEnvelope as h, CustomFieldValue as i, CustomFilterValue as j, EducationRequirement as k, JobCatalogPagination as l, JobCollectionChoiceList as m, JobCollectionFieldDefinition as n, JobCompany as o, JobCustomEmploymentType as p, OfficeLocation as q, OffsetPagination as r, PublicJobCard as s, RelatedSearch as t, RemotePermit as u, RemoteTimezone as v, ResolvedJobCollectionField as w, StorefrontPagination as x };
168
+ export type { CustomFieldValues as C, EmploymentType as E, JobSort as J, ListEnvelope as L, ObjectReferenceFilter as O, PublicJob as P, RemoteOption as R, Seniority as S, CustomFieldFilter as a, JobCollectionChoiceQuery as b, JobsListQuery as c, JobCardListEnvelope as d, JobRetrieveQuery as e, JobsSearchBody as f, JobCardSearchEnvelope as g, JobsSimilarQuery as h, SearchEnvelope as i, CustomFieldValue as j, CustomFilterValue as k, EducationRequirement as l, JobCapability as m, JobCatalogPagination as n, JobCollectionChoiceList as o, JobCollectionFieldDefinition as p, JobCompany as q, JobCustomEmploymentType as r, OfficeLocation as s, OffsetPagination as t, PublicJobCard as u, RelatedSearch as v, RemotePermit as w, RemoteTimezone as x, ResolvedJobCollectionField as y, StorefrontPagination as z };
package/dist/paths.d.mts CHANGED
@@ -134,6 +134,11 @@ declare function blogAuthorPath(authorSlug: string): string;
134
134
  * Only the handle is encoded.
135
135
  */
136
136
  declare function talentProfilePath(handle: string): string;
137
+ /**
138
+ * Talent location page (`/talent/locations/<place>`): the candidates who live
139
+ * in a place. Pass the place's `canonicalSlug` from the talent place list.
140
+ */
141
+ declare function talentLocationPath(placeSlug: string): string;
137
142
  /**
138
143
  * Static top-level board paths (indexed marketing + index surfaces). Kept
139
144
  * here so the sitemap and consumers share one definition of the chrome
@@ -155,6 +160,7 @@ declare const BOARD_PATHS: {
155
160
  readonly cookiePolicy: "/cookie-policy";
156
161
  readonly impressum: "/impressum";
157
162
  readonly talent: "/talent";
163
+ readonly talentLocations: "/talent/locations";
158
164
  readonly employers: "/employers";
159
165
  /**
160
166
  * Alert-email surfaces. Promoted out of raw literals in
@@ -188,4 +194,4 @@ declare function goAlertsConfirmPath(): string;
188
194
  */
189
195
  declare function boardUrl(origin: string, path: string): string;
190
196
 
191
- export { BOARD_PATHS, type SuggestionPathInput, type SuggestionPathOptions, type SuggestionPathScope, blogAuthorPath, blogPostPath, blogTagPath, boardUrl, companyMarketPath, companyPath, companySalaryPath, encodePathSegment, goAlertsConfirmPath, goAlertsManagePath, goJobPath, jobDetailPath, jobsCategoryPath, jobsLocationCategoryPath, jobsLocationPath, jobsLocationSkillPath, jobsSkillPath, salaryLocationPath, salarySkillPath, salaryTitlePath, suggestionPath, talentProfilePath };
197
+ export { BOARD_PATHS, type SuggestionPathInput, type SuggestionPathOptions, type SuggestionPathScope, blogAuthorPath, blogPostPath, blogTagPath, boardUrl, companyMarketPath, companyPath, companySalaryPath, encodePathSegment, goAlertsConfirmPath, goAlertsManagePath, goJobPath, jobDetailPath, jobsCategoryPath, jobsLocationCategoryPath, jobsLocationPath, jobsLocationSkillPath, jobsSkillPath, salaryLocationPath, salarySkillPath, salaryTitlePath, suggestionPath, talentLocationPath, talentProfilePath };
package/dist/paths.d.ts CHANGED
@@ -134,6 +134,11 @@ declare function blogAuthorPath(authorSlug: string): string;
134
134
  * Only the handle is encoded.
135
135
  */
136
136
  declare function talentProfilePath(handle: string): string;
137
+ /**
138
+ * Talent location page (`/talent/locations/<place>`): the candidates who live
139
+ * in a place. Pass the place's `canonicalSlug` from the talent place list.
140
+ */
141
+ declare function talentLocationPath(placeSlug: string): string;
137
142
  /**
138
143
  * Static top-level board paths (indexed marketing + index surfaces). Kept
139
144
  * here so the sitemap and consumers share one definition of the chrome
@@ -155,6 +160,7 @@ declare const BOARD_PATHS: {
155
160
  readonly cookiePolicy: "/cookie-policy";
156
161
  readonly impressum: "/impressum";
157
162
  readonly talent: "/talent";
163
+ readonly talentLocations: "/talent/locations";
158
164
  readonly employers: "/employers";
159
165
  /**
160
166
  * Alert-email surfaces. Promoted out of raw literals in
@@ -188,4 +194,4 @@ declare function goAlertsConfirmPath(): string;
188
194
  */
189
195
  declare function boardUrl(origin: string, path: string): string;
190
196
 
191
- export { BOARD_PATHS, type SuggestionPathInput, type SuggestionPathOptions, type SuggestionPathScope, blogAuthorPath, blogPostPath, blogTagPath, boardUrl, companyMarketPath, companyPath, companySalaryPath, encodePathSegment, goAlertsConfirmPath, goAlertsManagePath, goJobPath, jobDetailPath, jobsCategoryPath, jobsLocationCategoryPath, jobsLocationPath, jobsLocationSkillPath, jobsSkillPath, salaryLocationPath, salarySkillPath, salaryTitlePath, suggestionPath, talentProfilePath };
197
+ export { BOARD_PATHS, type SuggestionPathInput, type SuggestionPathOptions, type SuggestionPathScope, blogAuthorPath, blogPostPath, blogTagPath, boardUrl, companyMarketPath, companyPath, companySalaryPath, encodePathSegment, goAlertsConfirmPath, goAlertsManagePath, goJobPath, jobDetailPath, jobsCategoryPath, jobsLocationCategoryPath, jobsLocationPath, jobsLocationSkillPath, jobsSkillPath, salaryLocationPath, salarySkillPath, salaryTitlePath, suggestionPath, talentLocationPath, talentProfilePath };
package/dist/paths.js CHANGED
@@ -42,6 +42,7 @@ __export(paths_exports, {
42
42
  salarySkillPath: () => salarySkillPath,
43
43
  salaryTitlePath: () => salaryTitlePath,
44
44
  suggestionPath: () => suggestionPath,
45
+ talentLocationPath: () => talentLocationPath,
45
46
  talentProfilePath: () => talentProfilePath
46
47
  });
47
48
  module.exports = __toCommonJS(paths_exports);
@@ -131,6 +132,9 @@ function blogAuthorPath(authorSlug) {
131
132
  function talentProfilePath(handle) {
132
133
  return `/p/${encodePathSegment(handle)}`;
133
134
  }
135
+ function talentLocationPath(placeSlug) {
136
+ return `/talent/locations/${encodePathSegment(placeSlug)}`;
137
+ }
134
138
  var BOARD_PATHS = {
135
139
  home: "/",
136
140
  jobs: "/jobs",
@@ -147,6 +151,7 @@ var BOARD_PATHS = {
147
151
  cookiePolicy: "/cookie-policy",
148
152
  impressum: "/impressum",
149
153
  talent: "/talent",
154
+ talentLocations: "/talent/locations",
150
155
  employers: "/employers",
151
156
  /**
152
157
  * Alert-email surfaces. Promoted out of raw literals in
package/dist/paths.mjs CHANGED
@@ -21,8 +21,9 @@ import {
21
21
  salarySkillPath,
22
22
  salaryTitlePath,
23
23
  suggestionPath,
24
+ talentLocationPath,
24
25
  talentProfilePath
25
- } from "./chunk-XXQCESMU.mjs";
26
+ } from "./chunk-JFDWTTOQ.mjs";
26
27
  export {
27
28
  BOARD_PATHS,
28
29
  blogAuthorPath,
@@ -46,5 +47,6 @@ export {
46
47
  salarySkillPath,
47
48
  salaryTitlePath,
48
49
  suggestionPath,
50
+ talentLocationPath,
49
51
  talentProfilePath
50
52
  };
@@ -119,6 +119,7 @@ var BOARD_PATHS = {
119
119
  cookiePolicy: "/cookie-policy",
120
120
  impressum: "/impressum",
121
121
  talent: "/talent",
122
+ talentLocations: "/talent/locations",
122
123
  employers: "/employers",
123
124
  /**
124
125
  * Alert-email surfaces. Promoted out of raw literals in
@@ -26,8 +26,8 @@ import {
26
26
  parseTanStackRoutes,
27
27
  sameParamSet,
28
28
  validateManifest
29
- } from "./chunk-5KCWHENV.mjs";
30
- import "./chunk-XXQCESMU.mjs";
29
+ } from "./chunk-2KD2CWFL.mjs";
30
+ import "./chunk-JFDWTTOQ.mjs";
31
31
  export {
32
32
  ALL_ROLES,
33
33
  CANONICAL_MANIFEST,
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DHa5r3B0.js';
1
+ import { S as Schemas } from './_spec-DiQvT7IN.js';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DHa5r3B0.mjs';
1
+ import { S as Schemas } from './_spec-DiQvT7IN.mjs';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DHa5r3B0.js';
1
+ import { S as Schemas } from './_spec-DiQvT7IN.js';
2
2
 
3
3
  /**
4
4
  * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-DHa5r3B0.mjs';
1
+ import { S as Schemas } from './_spec-DiQvT7IN.mjs';
2
2
 
3
3
  /**
4
4
  * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
@@ -1,5 +1,5 @@
1
- import { B as BoardSeo } from './seo-gY8y9RMw.mjs';
2
- import './_spec-DHa5r3B0.mjs';
1
+ import { B as BoardSeo } from './seo-DMpAStWc.mjs';
2
+ import './_spec-DiQvT7IN.mjs';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
@@ -1,5 +1,5 @@
1
- import { B as BoardSeo } from './seo-ynqiQmby.js';
2
- import './_spec-DHa5r3B0.js';
1
+ import { B as BoardSeo } from './seo-BOPoZApt.js';
2
+ import './_spec-DiQvT7IN.js';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
package/dist/seo.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DylAbc0L.mjs';
2
- import { e as JsonLdObject } from './breadcrumbs-B6yhrHJV.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-B6yhrHJV.mjs';
4
- import './_spec-DHa5r3B0.mjs';
5
- import './board-Bpze3b50.mjs';
6
- import './jobs-CMK-DZg3.mjs';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DGa6Wk08.mjs';
2
+ import { e as JsonLdObject } from './breadcrumbs-2A7uGl7p.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-2A7uGl7p.mjs';
4
+ import './_spec-DiQvT7IN.mjs';
5
+ import './board-DM-vktAo.mjs';
6
+ import './jobs-DsO3htwV.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-wxhB8zAH.js';
2
- import { e as JsonLdObject } from './breadcrumbs-15j5xvmN.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-15j5xvmN.js';
4
- import './_spec-DHa5r3B0.js';
5
- import './board-DHsd92Gy.js';
6
- import './jobs-CIrTcMjw.js';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-BqUwoJRF.js';
2
+ import { e as JsonLdObject } from './breadcrumbs-BBwMLBGL.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-BBwMLBGL.js';
4
+ import './_spec-DiQvT7IN.js';
5
+ import './board-BNJ5Bsx2.js';
6
+ import './jobs-DQZEGLIC.js';
7
7
 
8
8
  /**
9
9
  * Blog structured data on the `@cavuno/board` wire types, transcribed from
package/dist/seo.js CHANGED
@@ -199,6 +199,7 @@ var BOARD_PATHS = {
199
199
  cookiePolicy: "/cookie-policy",
200
200
  impressum: "/impressum",
201
201
  talent: "/talent",
202
+ talentLocations: "/talent/locations",
202
203
  employers: "/employers",
203
204
  /**
204
205
  * Alert-email surfaces. Promoted out of raw literals in
@@ -262,11 +263,11 @@ function buildJobBreadcrumbs(job) {
262
263
  ];
263
264
  let lastPlaceSlug = null;
264
265
  for (const place of job.placeHierarchy) {
265
- lastPlaceSlug = place.slug;
266
+ lastPlaceSlug = place.canonicalSlug;
266
267
  crumbs.push({
267
268
  kind: "place",
268
269
  name: place.name,
269
- path: jobsLocationPath(place.slug)
270
+ path: jobsLocationPath(place.canonicalSlug)
270
271
  });
271
272
  }
272
273
  const primaryCategory = job.categories[0];
package/dist/seo.mjs CHANGED
@@ -17,11 +17,11 @@ import {
17
17
  skillSalaryJsonLd,
18
18
  sortBySeniority,
19
19
  titleSalaryJsonLd
20
- } from "./chunk-KDFKVWTZ.mjs";
20
+ } from "./chunk-JTFUOGWE.mjs";
21
21
  import {
22
22
  boardUrl,
23
23
  jobDetailPath
24
- } from "./chunk-XXQCESMU.mjs";
24
+ } from "./chunk-JFDWTTOQ.mjs";
25
25
 
26
26
  // src/seo/blog.ts
27
27
  function createBlogArticleJsonLd({
package/dist/server.d.mts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-DHa5r3B0.mjs';
3
- import './search-DBQApXN1.mjs';
4
- import './jobs-CMK-DZg3.mjs';
5
- import './board-Bpze3b50.mjs';
6
- import './seo-gY8y9RMw.mjs';
7
- import './blog-DylAbc0L.mjs';
2
+ import './_spec-DiQvT7IN.mjs';
3
+ import './search-g3oH9aPu.mjs';
4
+ import './jobs-DsO3htwV.mjs';
5
+ import './board-DM-vktAo.mjs';
6
+ import './seo-DMpAStWc.mjs';
7
+ import './blog-DGa6Wk08.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-DHa5r3B0.js';
3
- import './search-666oDd7H.js';
4
- import './jobs-CIrTcMjw.js';
5
- import './board-DHsd92Gy.js';
6
- import './seo-ynqiQmby.js';
7
- import './blog-wxhB8zAH.js';
2
+ import './_spec-DiQvT7IN.js';
3
+ import './search-C3DpF31i.js';
4
+ import './jobs-DQZEGLIC.js';
5
+ import './board-BNJ5Bsx2.js';
6
+ import './seo-BOPoZApt.js';
7
+ import './blog-BqUwoJRF.js';
8
8
 
9
9
  /**
10
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-DHa5r3B0.mjs';
3
- import './search-DBQApXN1.mjs';
4
- import './jobs-CMK-DZg3.mjs';
5
- import './board-Bpze3b50.mjs';
6
- import './seo-gY8y9RMw.mjs';
7
- import './blog-DylAbc0L.mjs';
2
+ import './_spec-DiQvT7IN.mjs';
3
+ import './search-g3oH9aPu.mjs';
4
+ import './jobs-DsO3htwV.mjs';
5
+ import './board-DM-vktAo.mjs';
6
+ import './seo-DMpAStWc.mjs';
7
+ import './blog-DGa6Wk08.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-DHa5r3B0.js';
3
- import './search-666oDd7H.js';
4
- import './jobs-CIrTcMjw.js';
5
- import './board-DHsd92Gy.js';
6
- import './seo-ynqiQmby.js';
7
- import './blog-wxhB8zAH.js';
2
+ import './_spec-DiQvT7IN.js';
3
+ import './search-C3DpF31i.js';
4
+ import './jobs-DQZEGLIC.js';
5
+ import './board-BNJ5Bsx2.js';
6
+ import './seo-BOPoZApt.js';
7
+ import './blog-BqUwoJRF.js';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.js CHANGED
@@ -240,6 +240,7 @@ var BOARD_PATHS = {
240
240
  cookiePolicy: "/cookie-policy",
241
241
  impressum: "/impressum",
242
242
  talent: "/talent",
243
+ talentLocations: "/talent/locations",
243
244
  employers: "/employers",
244
245
  /**
245
246
  * Alert-email surfaces. Promoted out of raw literals in
package/dist/sitemap.mjs CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  salaryLocationPath,
20
20
  salarySkillPath,
21
21
  salaryTitlePath
22
- } from "./chunk-XXQCESMU.mjs";
22
+ } from "./chunk-JFDWTTOQ.mjs";
23
23
 
24
24
  // src/sitemap/xml.ts
25
25
  var SITEMAP_BUCKETS = [
@@ -1,5 +1,5 @@
1
- import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-DBQApXN1.mjs';
2
- import './_spec-DHa5r3B0.mjs';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-g3oH9aPu.mjs';
2
+ import './_spec-DiQvT7IN.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-666oDd7H.js';
2
- import './_spec-DHa5r3B0.js';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-C3DpF31i.js';
2
+ import './_spec-DiQvT7IN.js';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/suggest` — framework-agnostic headless search-suggest
@@ -100,6 +100,7 @@ var BOARD_PATHS = {
100
100
  cookiePolicy: "/cookie-policy",
101
101
  impressum: "/impressum",
102
102
  talent: "/talent",
103
+ talentLocations: "/talent/locations",
103
104
  employers: "/employers",
104
105
  /**
105
106
  * Alert-email surfaces. Promoted out of raw literals in
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  compileManifest
3
- } from "./chunk-5KCWHENV.mjs";
4
- import "./chunk-XXQCESMU.mjs";
3
+ } from "./chunk-2KD2CWFL.mjs";
4
+ import "./chunk-JFDWTTOQ.mjs";
5
5
 
6
6
  // src/well-known/handler.ts
7
7
  var WELL_KNOWN_CACHE_CONTROL = "public, max-age=300";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "4.47.0",
3
+ "version": "4.49.0",
4
4
  "description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -44,6 +44,29 @@ Only `jobFunctions`, `placeSlugs`, and `remoteOptions` filter digest delivery. S
44
44
 
45
45
  `jobFunctions` are category and skill slugs (the `slug` of a category or skill, such as `engineering` or `media-and-communication`). A digest matches a job when any entry equals one of the job's category or skill slugs. Prefer sending slugs. If you send display names or free-text keywords instead, the server slugifies each one when the alert is saved and matches it against the board's category and skill slugs, their aliases, and their board-language slugs. A display name that does not slugify to one of those (for example, a renamed category) is stored slugified and will not match, so send slugs whenever you have them. Alerts read back from the API therefore always carry slugs, so compare and display them as slugs.
46
46
 
47
+ ## Alert kinds, keywords, and anchor jobs
48
+
49
+ Every alert read back from either lane carries a read-only `kind`:
50
+
51
+ - `similar_job`: jobs similar to the job the visitor subscribed from. Subscribe from a job page with `context: { source: 'job_detail', jobId }` (or `job_apply_dialog`). `anchorJob` is that job as `{ id, slug, title }`, kept after the job closes. It is `null` for other kinds, and for an older similar-job alert whose job has not been captured yet.
52
+ - `search`: a board search for the alert's keywords, in `filters.query`. An older search alert can report `kind: 'search'` with `filters.query` `null`: its keyword is the single `jobFunctions` entry. When `query` is `null`, show the job functions as the alert's search instead.
53
+ - `filters`: jobs matching the stored filters exactly.
54
+
55
+ Send the query a search page ran as `filters.query` (on `board.me.alerts`, the top-level `query`), at most 200 characters after trimming. Keep sending the location and other filters alongside it.
56
+
57
+ ```ts snippet
58
+ await board.jobAlerts.subscribe({
59
+ email: 'ada@example.com',
60
+ consent: true,
61
+ filters: { query: 'Python developer', placeSlugs: ['berlin'] },
62
+ context: { source: 'jobs_list' },
63
+ });
64
+ ```
65
+
66
+ A sent `query` is stored as given (trimmed), so `front-end` reads back as `front-end`. A job-page `context` without a `jobId` cannot anchor a similar-job alert; with a `query` it makes a `search` alert. A client that predates `query` and sends the search keyword as its single `jobFunctions` entry, with a search-page `context.source`, still works: the server keeps that keyword as the alert's `query`.
67
+
68
+ On an update, `null` clears `query`, and omitting it keeps the stored keywords as long as `jobFunctions` are unchanged. An update never changes `kind`, except that giving a `filters` alert a `query` makes it a `search` alert. A `similar_job` alert takes no `query`: sending one, on subscribe with a job-page `context` or on an update, fails with `validation_bad_request` (400). To follow keywords instead, remove the similar-job alert and create a search alert. In alert lists, show the kind and, for similar-job alerts, link the anchor job.
69
+
47
70
  ## Anonymous lane: manage-token transport
48
71
 
49
72
  The read and write transports intentionally use different keys:
@@ -94,16 +117,19 @@ const { data: alerts } = await board.me.alerts.list();
94
117
  alerts[0]?.isActive;
95
118
  alerts[0]?.lastSentAt;
96
119
  alerts[0]?.filters;
120
+ alerts[0]?.kind;
121
+ alerts[0]?.anchorJob;
97
122
 
98
123
  const alert = await board.me.alerts.create({
99
124
  frequency: 'weekly',
100
- jobFunctions: ['engineering'],
125
+ query: 'Platform engineer',
101
126
  remoteOptions: ['remote'],
102
127
  });
103
128
 
104
129
  const current = await board.me.alerts.retrieve(alert.id);
105
130
  await board.me.alerts.update(alert.id, {
106
131
  frequency: 'weekly',
132
+ query: current.filters.query,
107
133
  jobFunctions: current.filters.jobFunctions,
108
134
  seniorityLevels: current.filters.seniorityLevels,
109
135
  remoteOptions: current.filters.remoteOptions,
@@ -20,9 +20,9 @@ widget uses `embed.jobs`.
20
20
 
21
21
  `JobsListQuery` accepts `limit` (1–100), `cursor`, `offset`, `companyId`,
22
22
  `companySlug`, `remoteOption`, `employmentType`, `seniority`, `location` with
23
- `radius` in kilometres, `category`, and `skill`. Repeated `seniority` values
24
- are OR-matched. `offset` takes precedence over `cursor`, so choose one paging
25
- mode per request.
23
+ `radius` in kilometres or `defaultRadius`, `category`, and `skill`. Repeated
24
+ `seniority` values are OR-matched. `offset` takes precedence over `cursor`, so
25
+ choose one paging mode per request.
26
26
 
27
27
  ```ts snippet
28
28
  const first = await board.jobs.list({
@@ -58,6 +58,24 @@ const page = await board.jobs.list({
58
58
  });
59
59
  ```
60
60
 
61
+ ### List a location page in one request
62
+
63
+ `defaultRadius: true` with a `location` and no `radius` widens a city or
64
+ locality to the market default distance: 25 miles (40.2336 km) in the US, GB,
65
+ LR and MM, 50 km elsewhere. Regions, countries and places without coordinates
66
+ are not widened, and an explicit `radius` wins. The server picks the distance
67
+ from the place it already resolves, so a location page can fetch its jobs in
68
+ parallel with `taxonomy.places.resolve` instead of after it. `jobs.search` takes the
69
+ same flag in `filters`.
70
+
71
+ ```ts snippet
72
+ const nearby = await board.jobs.list({
73
+ location: 'houston-texas-united-states',
74
+ defaultRadius: true,
75
+ limit: 20,
76
+ });
77
+ ```
78
+
61
79
  ## Search
62
80
 
63
81
  `jobs.search` posts `JobsSearchBody`: free-text `query`, structured `filters`,
@@ -88,6 +106,18 @@ job.company?.slug;
88
106
  const rail = await board.jobs.similar('senior-chef', { limit: 5 });
89
107
  ```
90
108
 
109
+ A starter that renders the country-gated Apply flow opts in per request with
110
+ `capabilities: ['apply-gateway-v1']`. The opt-in travels in the URL, so the
111
+ response stays shared-cacheable. The older `x-cavuno-board-capabilities`
112
+ header returns the same body but is never cached.
113
+
114
+ ```ts snippet
115
+ const gated = await board.jobs.retrieve('senior-chef', {
116
+ capabilities: ['apply-gateway-v1'],
117
+ });
118
+ gated.applyAction; // 'gateway_external' | 'gateway_native' | …
119
+ ```
120
+
91
121
  ## Surface candidate gating
92
122
 
93
123
  On a gated board, `gatedCount` reports results withheld from the current
@@ -82,6 +82,19 @@ Pause with a concrete blocker when the board identifier or a required test crede
82
82
 
83
83
  **Complete when:** doctor, direct API probes, implemented-surface checks, and the production-build probe all pass or each skipped credentialed check is reported.
84
84
 
85
+ ## Reporting problems
86
+
87
+ When Cavuno itself gets in the way (a missing capability, unclear or wrong documentation, a surprising response, an unhelpful error, a bug or slow performance), report it, even if you found a workaround. `POST https://api.cavuno.com/v1/feedback` accepts [Agent Feedback Protocol v0.1](https://trybackloop.com/spec/) reports without credentials; the discovery document is at `https://api.cavuno.com/.well-known/agent-feedback`.
88
+
89
+ ```bash
90
+ curl https://api.cavuno.com/v1/feedback \
91
+ -X POST \
92
+ -H "Content-Type: application/json" \
93
+ -d '{ "type": "unclear_documentation", "goal": "What you were trying to do", "message": "What got in the way", "agent": { "name": "my-agent", "model": "model-name" } }'
94
+ ```
95
+
96
+ `type`, `goal` and `message` are required; fill `agent.name` and `agent.model`. Up to 20 reports every 5 minutes. Never include credentials, `pk_…` keys, personal data or your user's private content. Send the report, then continue with the task.
97
+
85
98
  ## Cavuno SDK reference
86
99
 
87
100
  For setup and API details beyond this workflow, use the [Cavuno Board SDK documentation](https://cavuno.com/docs/sdk).
@@ -130,6 +130,8 @@ await board.me.conversations.start({
130
130
 
131
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
132
 
133
+ `lastActive` on directory cards and profiles is a coarse bucket (`today`, `this_week`, `this_month`, `last_3_months`, `over_3_months`) for a signed-in employer looking at a candidate who is actively looking or open to offers, and `null` otherwise. It stays on redacted cards. Render it as a short label such as "Active this week" and hide it when `null`.
134
+
133
135
  ```ts snippet
134
136
  const named = await board.talent.retrieve('jane-doe');
135
137
  const opaque = await board.talent.retrieve('bu_candidate');
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.47.0",
2
+ "version": "4.49.0",
3
3
  "skills": [
4
4
  {
5
5
  "name": "cavuno-board-account",