@cavuno/board 4.22.0 → 4.24.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 (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +15 -0
  3. package/dist/{_spec-p1bcDr9R.d.mts → _spec-BZQuYYpQ.d.mts} +4 -2
  4. package/dist/{_spec-p1bcDr9R.d.ts → _spec-BZQuYYpQ.d.ts} +4 -2
  5. package/dist/{blog-CsI8GdJS.d.mts → blog-DR7v6Bq7.d.mts} +1 -1
  6. package/dist/{blog-DB4YIfn4.d.ts → blog-DrBeKr1S.d.ts} +1 -1
  7. package/dist/{board-Dq9gD7qr.d.ts → board-ByNdDHrH.d.ts} +2 -2
  8. package/dist/{board-CuIyeFsj.d.mts → board-D8e-h3qJ.d.mts} +2 -2
  9. package/dist/{breadcrumbs-CyCZ8N8_.d.ts → breadcrumbs-Dzt5dJrV.d.ts} +2 -2
  10. package/dist/{breadcrumbs-B_WTKaIk.d.mts → breadcrumbs-WLAHK942.d.mts} +2 -2
  11. package/dist/browser/cavuno-board.global.min.js +1 -1
  12. package/dist/filters.d.mts +2 -2
  13. package/dist/filters.d.ts +2 -2
  14. package/dist/format.d.mts +4 -4
  15. package/dist/format.d.ts +4 -4
  16. package/dist/index.d.mts +13 -12
  17. package/dist/index.d.ts +13 -12
  18. package/dist/index.js +2 -2
  19. package/dist/index.mjs +2 -2
  20. package/dist/{jobs-C-sBPgNp.d.ts → jobs-C8Hkjwwr.d.ts} +1 -1
  21. package/dist/{jobs-Bv12BcSA.d.mts → jobs-CuhkEYri.d.mts} +1 -1
  22. package/dist/{search-CNeOnhWb.d.mts → search-BGonXaPj.d.mts} +1 -1
  23. package/dist/{search-W28d76OJ.d.ts → search-mFmRLLe9.d.ts} +1 -1
  24. package/dist/{seo-DAHd1ngs.d.ts → seo-BCqk_6iN.d.ts} +1 -1
  25. package/dist/{seo-BGHJcfev.d.mts → seo-Dw-7-wfY.d.mts} +1 -1
  26. package/dist/seo-files.d.mts +2 -2
  27. package/dist/seo-files.d.ts +2 -2
  28. package/dist/seo.d.mts +6 -6
  29. package/dist/seo.d.ts +6 -6
  30. package/dist/server.d.mts +6 -6
  31. package/dist/server.d.ts +6 -6
  32. package/dist/sitemap.d.mts +37 -7
  33. package/dist/sitemap.d.ts +37 -7
  34. package/dist/sitemap.js +34 -9
  35. package/dist/sitemap.mjs +34 -9
  36. package/dist/suggest.d.mts +2 -2
  37. package/dist/suggest.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/skills/cavuno-board-sitemap/SKILL.md +51 -2
  40. package/skills/manifest.json +1 -1
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { S as Schemas, c as components } from './_spec-p1bcDr9R.js';
2
- import { F as FetchOptions, S as StorageMode, B as BoardRequest, A as Awaitable, L as Logger, a as BoardClient, b as SearchSuggestQuery } from './search-W28d76OJ.js';
3
- export { c as ACCESS_TOKEN_KEY, d as BOARD_ACCESS_GRANT_KEY, C as CompanySuggestion, e as CustomStorage, M as MarketSuggestion, R as REFRESH_TOKEN_KEY, f as SearchSuggestType, g as SuggestResult, h as SuggestionItem, T as TermSuggestion } from './search-W28d76OJ.js';
4
- import { c as CompaniesListQuery, d as CompanyListEnvelope, e as CompaniesSearchBody, f as CompanyJobsListQuery, g as CompanySimilarQuery, h as CompanyMarketsListQuery, i as SalaryDetailQuery } from './board-Dq9gD7qr.js';
5
- export { a as CompanyCategorySalary, j as CompanyMarket, k as CompanyMarketRef, b as CompanySalary, l as CompanySalarySummary, C as CustomFieldDefinition, m as CustomFieldOption, n as CustomFieldType, L as LocationSalaryDetail, o as LocationSkillsIndex, p as LocationTitlesIndex, P as PublicBoard, q as PublicBoardAds, r as PublicBoardAnalytics, s as PublicBoardFeatures, t as PublicBoardJobForm, u as PublicCompany, v as PublicCompanyDetail, w as PublicCompanyMembership, x as SalaryCompany, y as SalaryLocation, z as SalarySkill, A as SalaryTitle, B as SkillLocationSalary, D as SkillLocationsIndex, S as SkillSalaryDetail, E as TitleLocationSalary, F as TitleLocationsIndex, T as TitleSalaryDetail } from './board-Dq9gD7qr.js';
6
- export { B as BoardSeo } from './seo-DAHd1ngs.js';
7
- import { R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, a as JobsListQuery, b as JobCardListEnvelope, c as JobsSearchBody, d as JobCardSearchEnvelope, e as JobsSimilarQuery, f as SearchEnvelope } from './jobs-C-sBPgNp.js';
8
- export { g as CustomFieldValue, C as CustomFieldValues, h as EducationRequirement, i as JobCatalogPagination, j as JobCompany, J as JobSort, O as OfficeLocation, k as OffsetPagination, P as PublicJob, l as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-C-sBPgNp.js';
9
- import { a as BlogPostsListQuery, b as BlogSimilarQuery, c as BlogSearchBody } from './blog-DB4YIfn4.js';
10
- export { B as BlogAuthorEmbed, d as BlogTagEmbed, e as PublicBlogAdjacentPosts, f as PublicBlogAuthor, g as PublicBlogPost, P as PublicBlogPostSummary, h as PublicBlogTag } from './blog-DB4YIfn4.js';
1
+ import { S as Schemas, c as components } from './_spec-BZQuYYpQ.js';
2
+ import { F as FetchOptions, S as StorageMode, B as BoardRequest, A as Awaitable, L as Logger, a as BoardClient, b as SearchSuggestQuery } from './search-mFmRLLe9.js';
3
+ export { c as ACCESS_TOKEN_KEY, d as BOARD_ACCESS_GRANT_KEY, C as CompanySuggestion, e as CustomStorage, M as MarketSuggestion, R as REFRESH_TOKEN_KEY, f as SearchSuggestType, g as SuggestResult, h as SuggestionItem, T as TermSuggestion } from './search-mFmRLLe9.js';
4
+ import { c as CompaniesListQuery, d as CompanyListEnvelope, e as CompaniesSearchBody, f as CompanyJobsListQuery, g as CompanySimilarQuery, h as CompanyMarketsListQuery, i as SalaryDetailQuery } from './board-ByNdDHrH.js';
5
+ export { a as CompanyCategorySalary, j as CompanyMarket, k as CompanyMarketRef, b as CompanySalary, l as CompanySalarySummary, C as CustomFieldDefinition, m as CustomFieldOption, n as CustomFieldType, L as LocationSalaryDetail, o as LocationSkillsIndex, p as LocationTitlesIndex, P as PublicBoard, q as PublicBoardAds, r as PublicBoardAnalytics, s as PublicBoardFeatures, t as PublicBoardJobForm, u as PublicCompany, v as PublicCompanyDetail, w as PublicCompanyMembership, x as SalaryCompany, y as SalaryLocation, z as SalarySkill, A as SalaryTitle, B as SkillLocationSalary, D as SkillLocationsIndex, S as SkillSalaryDetail, E as TitleLocationSalary, F as TitleLocationsIndex, T as TitleSalaryDetail } from './board-ByNdDHrH.js';
6
+ export { B as BoardSeo } from './seo-BCqk_6iN.js';
7
+ import { R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, a as JobsListQuery, b as JobCardListEnvelope, c as JobsSearchBody, d as JobCardSearchEnvelope, e as JobsSimilarQuery, f as SearchEnvelope } from './jobs-C8Hkjwwr.js';
8
+ export { g as CustomFieldValue, C as CustomFieldValues, h as EducationRequirement, i as JobCatalogPagination, j as JobCompany, J as JobSort, O as OfficeLocation, k as OffsetPagination, P as PublicJob, l as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-C8Hkjwwr.js';
9
+ import { a as BlogPostsListQuery, b as BlogSimilarQuery, c as BlogSearchBody } from './blog-DrBeKr1S.js';
10
+ export { B as BlogAuthorEmbed, d as BlogTagEmbed, e as PublicBlogAdjacentPosts, f as PublicBlogAuthor, g as PublicBlogPost, P as PublicBlogPostSummary, h as PublicBlogTag } from './blog-DrBeKr1S.js';
11
11
 
12
12
  /**
13
13
  * Well-known `<domain>_<snake_reason>` codes the Board API sends, grouped by
@@ -150,7 +150,7 @@ declare function paginate<Q extends Record<string, unknown>, P extends PageShape
150
150
  * constant because the package is platform-neutral and cannot read
151
151
  * package.json at runtime.
152
152
  */
153
- declare const SDK_VERSION = "4.22.0";
153
+ declare const SDK_VERSION = "4.24.0";
154
154
 
155
155
  type SavedJob = Schemas['SavedJob'];
156
156
  type SavedJobsListQuery = {
@@ -922,7 +922,7 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
922
922
  client: BoardClient;
923
923
  /**
924
924
  * Board context — identity, brand (`logoUrl` + favicon `icons`), language,
925
- * features, analytics, and AdSense (`ads.enabled` + `ads.clientId`).
925
+ * features, analytics, and AdSense (`ads.enabled`, `ads.clientId`, and `ads.defaultSlotId`).
926
926
  * Per-placement slot ids are not on this resource.
927
927
  *
928
928
  * @example
@@ -980,6 +980,7 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
980
980
  ads: {
981
981
  enabled: boolean;
982
982
  clientId: string | null;
983
+ defaultSlotId: string | null;
983
984
  };
984
985
  customFields: {
985
986
  job: components["schemas"]["CustomFieldDefinition"][];
package/dist/index.js CHANGED
@@ -358,7 +358,7 @@ async function clearSession(storage) {
358
358
  }
359
359
 
360
360
  // src/version.ts
361
- var SDK_VERSION = "4.22.0";
361
+ var SDK_VERSION = "4.24.0";
362
362
 
363
363
  // src/client.ts
364
364
  function isRawBody(body) {
@@ -3477,7 +3477,7 @@ function createBoardClient(options) {
3477
3477
  client,
3478
3478
  /**
3479
3479
  * Board context — identity, brand (`logoUrl` + favicon `icons`), language,
3480
- * features, analytics, and AdSense (`ads.enabled` + `ads.clientId`).
3480
+ * features, analytics, and AdSense (`ads.enabled`, `ads.clientId`, and `ads.defaultSlotId`).
3481
3481
  * Per-placement slot ids are not on this resource.
3482
3482
  *
3483
3483
  * @example
package/dist/index.mjs CHANGED
@@ -42,7 +42,7 @@ function toSearchParams(query) {
42
42
  }
43
43
 
44
44
  // src/version.ts
45
- var SDK_VERSION = "4.22.0";
45
+ var SDK_VERSION = "4.24.0";
46
46
 
47
47
  // src/client.ts
48
48
  function isRawBody(body) {
@@ -3131,7 +3131,7 @@ function createBoardClient(options) {
3131
3131
  client,
3132
3132
  /**
3133
3133
  * Board context — identity, brand (`logoUrl` + favicon `icons`), language,
3134
- * features, analytics, and AdSense (`ads.enabled` + `ads.clientId`).
3134
+ * features, analytics, and AdSense (`ads.enabled`, `ads.clientId`, and `ads.defaultSlotId`).
3135
3135
  * Per-placement slot ids are not on this resource.
3136
3136
  *
3137
3137
  * @example
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-p1bcDr9R.js';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.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-p1bcDr9R.mjs';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.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-p1bcDr9R.mjs';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.mjs';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-p1bcDr9R.js';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.js';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-p1bcDr9R.js';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.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-p1bcDr9R.mjs';
1
+ import { S as Schemas } from './_spec-BZQuYYpQ.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-BGHJcfev.mjs';
2
- import './_spec-p1bcDr9R.mjs';
1
+ import { B as BoardSeo } from './seo-Dw-7-wfY.mjs';
2
+ import './_spec-BZQuYYpQ.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-DAHd1ngs.js';
2
- import './_spec-p1bcDr9R.js';
1
+ import { B as BoardSeo } from './seo-BCqk_6iN.js';
2
+ import './_spec-BZQuYYpQ.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-CsI8GdJS.mjs';
2
- import { e as JsonLdObject } from './breadcrumbs-B_WTKaIk.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-B_WTKaIk.mjs';
4
- import './_spec-p1bcDr9R.mjs';
5
- import './board-CuIyeFsj.mjs';
6
- import './jobs-Bv12BcSA.mjs';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DR7v6Bq7.mjs';
2
+ import { e as JsonLdObject } from './breadcrumbs-WLAHK942.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-WLAHK942.mjs';
4
+ import './_spec-BZQuYYpQ.mjs';
5
+ import './board-D8e-h3qJ.mjs';
6
+ import './jobs-CuhkEYri.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-DB4YIfn4.js';
2
- import { e as JsonLdObject } from './breadcrumbs-CyCZ8N8_.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-CyCZ8N8_.js';
4
- import './_spec-p1bcDr9R.js';
5
- import './board-Dq9gD7qr.js';
6
- import './jobs-C-sBPgNp.js';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DrBeKr1S.js';
2
+ import { e as JsonLdObject } from './breadcrumbs-Dzt5dJrV.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-Dzt5dJrV.js';
4
+ import './_spec-BZQuYYpQ.js';
5
+ import './board-ByNdDHrH.js';
6
+ import './jobs-C8Hkjwwr.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-p1bcDr9R.mjs';
3
- import './search-CNeOnhWb.mjs';
4
- import './board-CuIyeFsj.mjs';
5
- import './jobs-Bv12BcSA.mjs';
6
- import './seo-BGHJcfev.mjs';
7
- import './blog-CsI8GdJS.mjs';
2
+ import './_spec-BZQuYYpQ.mjs';
3
+ import './search-BGonXaPj.mjs';
4
+ import './board-D8e-h3qJ.mjs';
5
+ import './jobs-CuhkEYri.mjs';
6
+ import './seo-Dw-7-wfY.mjs';
7
+ import './blog-DR7v6Bq7.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-p1bcDr9R.js';
3
- import './search-W28d76OJ.js';
4
- import './board-Dq9gD7qr.js';
5
- import './jobs-C-sBPgNp.js';
6
- import './seo-DAHd1ngs.js';
7
- import './blog-DB4YIfn4.js';
2
+ import './_spec-BZQuYYpQ.js';
3
+ import './search-mFmRLLe9.js';
4
+ import './board-ByNdDHrH.js';
5
+ import './jobs-C8Hkjwwr.js';
6
+ import './seo-BCqk_6iN.js';
7
+ import './blog-DrBeKr1S.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-p1bcDr9R.mjs';
3
- import './search-CNeOnhWb.mjs';
4
- import './board-CuIyeFsj.mjs';
5
- import './jobs-Bv12BcSA.mjs';
6
- import './seo-BGHJcfev.mjs';
7
- import './blog-CsI8GdJS.mjs';
2
+ import './_spec-BZQuYYpQ.mjs';
3
+ import './search-BGonXaPj.mjs';
4
+ import './board-D8e-h3qJ.mjs';
5
+ import './jobs-CuhkEYri.mjs';
6
+ import './seo-Dw-7-wfY.mjs';
7
+ import './blog-DR7v6Bq7.mjs';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
@@ -70,6 +70,36 @@ declare const MIN_JOBS_PER_INDEXED_PAGE = 5;
70
70
  * urlset when a board lacks that content (valid, just zero URLs).
71
71
  */
72
72
  declare function listedBuckets(board: BoardSdk): Promise<SitemapBucket[]>;
73
+ /**
74
+ * One listed bucket, with the freshness stamp the board publishes for it.
75
+ *
76
+ * `lastModified` is present only on the mirror path, and only for the buckets
77
+ * the board tracks one for — the legacy fallback has no such stamp, so it
78
+ * yields bucket names alone. Feed these straight to `renderSitemapIndex` and
79
+ * each `<sitemap>` gets a `<lastmod>`.
80
+ */
81
+ interface ListedSitemapBucket {
82
+ bucket: SitemapBucket;
83
+ /** ISO 8601 timestamp of the newest content in the bucket, when known. */
84
+ lastModified?: string;
85
+ }
86
+ /**
87
+ * Like `listedBuckets`, but keeps each bucket's `lastModified`. Same two
88
+ * paths, same ordering, same error rules — the only difference is that the
89
+ * freshness stamp survives.
90
+ */
91
+ declare function listedBucketEntries(board: BoardSdk): Promise<ListedSitemapBucket[]>;
73
92
  declare function buildBucketUrls(board: BoardSdk, origin: string, bucket: SitemapBucket): Promise<string[]>;
93
+ /**
94
+ * Like `buildBucketUrls`, but keeps each URL's `lastModified` where the board
95
+ * publishes one. The result feeds `renderUrlset` directly, so every `<url>`
96
+ * that has a freshness stamp gets a `<lastmod>` — the signal crawlers use to
97
+ * prioritise recrawl across a large sitemap.
98
+ *
99
+ * On the legacy fallback path the catalog endpoints expose no per-URL stamp,
100
+ * so entries come back as `{ url }` only — identical output to
101
+ * `buildBucketUrls`, just in the wider shape.
102
+ */
103
+ declare function buildBucketEntries(board: BoardSdk, origin: string, bucket: SitemapBucket): Promise<SitemapUrlEntry[]>;
74
104
 
75
- export { MIN_JOBS_PER_INDEXED_PAGE, SITEMAP_BUCKETS, SITEMAP_CHUNK_SIZE, type SitemapBucket, type SitemapIndexEntry, type SitemapUrlEntry, bucketFilename, buildBucketUrls, chunk, listedBuckets, parseBucketFilename, renderSitemapIndex, renderUrlset, xmlEscape };
105
+ export { type ListedSitemapBucket, MIN_JOBS_PER_INDEXED_PAGE, SITEMAP_BUCKETS, SITEMAP_CHUNK_SIZE, type SitemapBucket, type SitemapIndexEntry, type SitemapUrlEntry, bucketFilename, buildBucketEntries, buildBucketUrls, chunk, listedBucketEntries, listedBuckets, parseBucketFilename, renderSitemapIndex, renderUrlset, xmlEscape };
package/dist/sitemap.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './_spec-p1bcDr9R.js';
3
- import './search-W28d76OJ.js';
4
- import './board-Dq9gD7qr.js';
5
- import './jobs-C-sBPgNp.js';
6
- import './seo-DAHd1ngs.js';
7
- import './blog-DB4YIfn4.js';
2
+ import './_spec-BZQuYYpQ.js';
3
+ import './search-mFmRLLe9.js';
4
+ import './board-ByNdDHrH.js';
5
+ import './jobs-C8Hkjwwr.js';
6
+ import './seo-BCqk_6iN.js';
7
+ import './blog-DrBeKr1S.js';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
@@ -70,6 +70,36 @@ declare const MIN_JOBS_PER_INDEXED_PAGE = 5;
70
70
  * urlset when a board lacks that content (valid, just zero URLs).
71
71
  */
72
72
  declare function listedBuckets(board: BoardSdk): Promise<SitemapBucket[]>;
73
+ /**
74
+ * One listed bucket, with the freshness stamp the board publishes for it.
75
+ *
76
+ * `lastModified` is present only on the mirror path, and only for the buckets
77
+ * the board tracks one for — the legacy fallback has no such stamp, so it
78
+ * yields bucket names alone. Feed these straight to `renderSitemapIndex` and
79
+ * each `<sitemap>` gets a `<lastmod>`.
80
+ */
81
+ interface ListedSitemapBucket {
82
+ bucket: SitemapBucket;
83
+ /** ISO 8601 timestamp of the newest content in the bucket, when known. */
84
+ lastModified?: string;
85
+ }
86
+ /**
87
+ * Like `listedBuckets`, but keeps each bucket's `lastModified`. Same two
88
+ * paths, same ordering, same error rules — the only difference is that the
89
+ * freshness stamp survives.
90
+ */
91
+ declare function listedBucketEntries(board: BoardSdk): Promise<ListedSitemapBucket[]>;
73
92
  declare function buildBucketUrls(board: BoardSdk, origin: string, bucket: SitemapBucket): Promise<string[]>;
93
+ /**
94
+ * Like `buildBucketUrls`, but keeps each URL's `lastModified` where the board
95
+ * publishes one. The result feeds `renderUrlset` directly, so every `<url>`
96
+ * that has a freshness stamp gets a `<lastmod>` — the signal crawlers use to
97
+ * prioritise recrawl across a large sitemap.
98
+ *
99
+ * On the legacy fallback path the catalog endpoints expose no per-URL stamp,
100
+ * so entries come back as `{ url }` only — identical output to
101
+ * `buildBucketUrls`, just in the wider shape.
102
+ */
103
+ declare function buildBucketEntries(board: BoardSdk, origin: string, bucket: SitemapBucket): Promise<SitemapUrlEntry[]>;
74
104
 
75
- export { MIN_JOBS_PER_INDEXED_PAGE, SITEMAP_BUCKETS, SITEMAP_CHUNK_SIZE, type SitemapBucket, type SitemapIndexEntry, type SitemapUrlEntry, bucketFilename, buildBucketUrls, chunk, listedBuckets, parseBucketFilename, renderSitemapIndex, renderUrlset, xmlEscape };
105
+ export { type ListedSitemapBucket, MIN_JOBS_PER_INDEXED_PAGE, SITEMAP_BUCKETS, SITEMAP_CHUNK_SIZE, type SitemapBucket, type SitemapIndexEntry, type SitemapUrlEntry, bucketFilename, buildBucketEntries, buildBucketUrls, chunk, listedBucketEntries, listedBuckets, parseBucketFilename, renderSitemapIndex, renderUrlset, xmlEscape };
package/dist/sitemap.js CHANGED
@@ -24,8 +24,10 @@ __export(sitemap_exports, {
24
24
  SITEMAP_BUCKETS: () => SITEMAP_BUCKETS,
25
25
  SITEMAP_CHUNK_SIZE: () => SITEMAP_CHUNK_SIZE,
26
26
  bucketFilename: () => bucketFilename,
27
+ buildBucketEntries: () => buildBucketEntries,
27
28
  buildBucketUrls: () => buildBucketUrls,
28
29
  chunk: () => chunk,
30
+ listedBucketEntries: () => listedBucketEntries,
29
31
  listedBuckets: () => listedBuckets,
30
32
  parseBucketFilename: () => parseBucketFilename,
31
33
  renderSitemapIndex: () => renderSitemapIndex,
@@ -305,34 +307,57 @@ function enumerateCompanies(board) {
305
307
  }
306
308
  var MIRROR_PAGE = 1e3;
307
309
  async function listedBuckets(board) {
310
+ const listed = await listedBucketEntries(board);
311
+ return listed.map((entry) => entry.bucket);
312
+ }
313
+ async function listedBucketEntries(board) {
308
314
  try {
309
315
  const index = await board.sitemap();
310
- const published = new Set(index.buckets.map((entry) => entry.bucket));
311
- return SITEMAP_BUCKETS.filter((bucket) => published.has(bucket));
316
+ const published = new Map(
317
+ index.buckets.map((entry) => [entry.bucket, entry.lastModified])
318
+ );
319
+ return SITEMAP_BUCKETS.filter((bucket) => published.has(bucket)).map(
320
+ (bucket) => {
321
+ const lastModified = published.get(bucket);
322
+ return lastModified === void 0 ? { bucket } : { bucket, lastModified };
323
+ }
324
+ );
312
325
  } catch (error) {
313
326
  if (!isNotFound(error)) throw error;
314
327
  const { features } = await board.context();
315
- return SITEMAP_BUCKETS.filter((b) => b !== "blog" || features.blog);
328
+ return SITEMAP_BUCKETS.filter((b) => b !== "blog" || features.blog).map(
329
+ (bucket) => ({ bucket })
330
+ );
316
331
  }
317
332
  }
318
333
  async function buildBucketUrls(board, origin, bucket) {
334
+ const entries = await buildBucketEntries(board, origin, bucket);
335
+ return entries.map((entry) => entry.url);
336
+ }
337
+ async function buildBucketEntries(board, origin, bucket) {
319
338
  try {
320
- return await mirrorBucketUrls(board, origin, bucket);
339
+ return await mirrorBucketEntries(board, origin, bucket);
321
340
  } catch (error) {
322
341
  if (!isNotFound(error)) throw error;
323
- return legacyBucketUrls(board, origin, bucket);
342
+ const urls = await legacyBucketUrls(board, origin, bucket);
343
+ return urls.map((url) => ({ url }));
324
344
  }
325
345
  }
326
- async function mirrorBucketUrls(board, origin, bucket) {
346
+ async function mirrorBucketEntries(board, origin, bucket) {
327
347
  const pages = paginate(
328
348
  (query, options) => board.sitemap.entries(bucket, query, options),
329
349
  { limit: MIRROR_PAGE }
330
350
  ).pages();
331
- const urls = [];
351
+ const entries = [];
332
352
  for await (const page of pages) {
333
- for (const entry of page.data) urls.push(`${origin}${entry.path}`);
353
+ for (const entry of page.data) {
354
+ const url = `${origin}${entry.path}`;
355
+ entries.push(
356
+ entry.lastModified === void 0 ? { url } : { url, lastModified: entry.lastModified }
357
+ );
358
+ }
334
359
  }
335
- return urls;
360
+ return entries;
336
361
  }
337
362
  async function legacyBucketUrls(board, origin, bucket) {
338
363
  switch (bucket) {
package/dist/sitemap.mjs CHANGED
@@ -178,34 +178,57 @@ function enumerateCompanies(board) {
178
178
  }
179
179
  var MIRROR_PAGE = 1e3;
180
180
  async function listedBuckets(board) {
181
+ const listed = await listedBucketEntries(board);
182
+ return listed.map((entry) => entry.bucket);
183
+ }
184
+ async function listedBucketEntries(board) {
181
185
  try {
182
186
  const index = await board.sitemap();
183
- const published = new Set(index.buckets.map((entry) => entry.bucket));
184
- return SITEMAP_BUCKETS.filter((bucket) => published.has(bucket));
187
+ const published = new Map(
188
+ index.buckets.map((entry) => [entry.bucket, entry.lastModified])
189
+ );
190
+ return SITEMAP_BUCKETS.filter((bucket) => published.has(bucket)).map(
191
+ (bucket) => {
192
+ const lastModified = published.get(bucket);
193
+ return lastModified === void 0 ? { bucket } : { bucket, lastModified };
194
+ }
195
+ );
185
196
  } catch (error) {
186
197
  if (!isNotFound(error)) throw error;
187
198
  const { features } = await board.context();
188
- return SITEMAP_BUCKETS.filter((b) => b !== "blog" || features.blog);
199
+ return SITEMAP_BUCKETS.filter((b) => b !== "blog" || features.blog).map(
200
+ (bucket) => ({ bucket })
201
+ );
189
202
  }
190
203
  }
191
204
  async function buildBucketUrls(board, origin, bucket) {
205
+ const entries = await buildBucketEntries(board, origin, bucket);
206
+ return entries.map((entry) => entry.url);
207
+ }
208
+ async function buildBucketEntries(board, origin, bucket) {
192
209
  try {
193
- return await mirrorBucketUrls(board, origin, bucket);
210
+ return await mirrorBucketEntries(board, origin, bucket);
194
211
  } catch (error) {
195
212
  if (!isNotFound(error)) throw error;
196
- return legacyBucketUrls(board, origin, bucket);
213
+ const urls = await legacyBucketUrls(board, origin, bucket);
214
+ return urls.map((url) => ({ url }));
197
215
  }
198
216
  }
199
- async function mirrorBucketUrls(board, origin, bucket) {
217
+ async function mirrorBucketEntries(board, origin, bucket) {
200
218
  const pages = paginate(
201
219
  (query, options) => board.sitemap.entries(bucket, query, options),
202
220
  { limit: MIRROR_PAGE }
203
221
  ).pages();
204
- const urls = [];
222
+ const entries = [];
205
223
  for await (const page of pages) {
206
- for (const entry of page.data) urls.push(`${origin}${entry.path}`);
224
+ for (const entry of page.data) {
225
+ const url = `${origin}${entry.path}`;
226
+ entries.push(
227
+ entry.lastModified === void 0 ? { url } : { url, lastModified: entry.lastModified }
228
+ );
229
+ }
207
230
  }
208
- return urls;
231
+ return entries;
209
232
  }
210
233
  async function legacyBucketUrls(board, origin, bucket) {
211
234
  switch (bucket) {
@@ -354,8 +377,10 @@ export {
354
377
  SITEMAP_BUCKETS,
355
378
  SITEMAP_CHUNK_SIZE,
356
379
  bucketFilename,
380
+ buildBucketEntries,
357
381
  buildBucketUrls,
358
382
  chunk,
383
+ listedBucketEntries,
359
384
  listedBuckets,
360
385
  parseBucketFilename,
361
386
  renderSitemapIndex,
@@ -1,5 +1,5 @@
1
- import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-CNeOnhWb.mjs';
2
- import './_spec-p1bcDr9R.mjs';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-BGonXaPj.mjs';
2
+ import './_spec-BZQuYYpQ.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-W28d76OJ.js';
2
- import './_spec-p1bcDr9R.js';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-mFmRLLe9.js';
2
+ import './_spec-BZQuYYpQ.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.22.0",
3
+ "version": "4.24.0",
4
4
  "description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -18,7 +18,10 @@ The pure XML tier exports `SITEMAP_BUCKETS`, `SITEMAP_CHUNK_SIZE` (45,000),
18
18
  `chunk`, `bucketFilename`, `parseBucketFilename`, `renderUrlset`, and
19
19
  `renderSitemapIndex`. The catalog tier exports `listedBuckets(board)` and
20
20
  `buildBucketUrls(board, origin, bucket)`; it walks the SDK and applies the
21
- hosted indexing policy.
21
+ hosted indexing policy. `listedBucketEntries(board)` and
22
+ `buildBucketEntries(board, origin, bucket)` are the freshness-preserving
23
+ siblings: same walk and same policy, but each result keeps its
24
+ `lastModified`.
22
25
 
23
26
  ## Serve the index
24
27
 
@@ -77,9 +80,55 @@ return xmlResponse(renderUrlset(page));
77
80
  serialize to ISO 8601. `renderSitemapIndex` accepts strings or
78
81
  `{ url, lastModified? }`. The hosted format omits `changefreq` and `priority`.
79
82
 
83
+ ## Emit `<lastmod>`
84
+
85
+ Freshness is the strongest recrawl-priority signal on a large sitemap, so
86
+ prefer the entries walkers. `buildBucketEntries` returns
87
+ `{ url, lastModified? }[]` that feeds `renderUrlset` unchanged, and
88
+ `listedBucketEntries` returns `{ bucket, lastModified? }[]` for the index.
89
+ The board publishes a stamp per URL and per bucket wherever it tracks one;
90
+ entries without one simply omit `<lastmod>`.
91
+
92
+ ```ts snippet
93
+ import {
94
+ SITEMAP_CHUNK_SIZE,
95
+ buildBucketEntries,
96
+ bucketFilename,
97
+ chunk,
98
+ listedBucketEntries,
99
+ renderSitemapIndex,
100
+ renderUrlset,
101
+ type SitemapIndexEntry,
102
+ } from '@cavuno/board/sitemap';
103
+
104
+ // Index: one <sitemap> per chunk, each carrying its bucket's stamp. Buckets
105
+ // over SITEMAP_CHUNK_SIZE produce -2, -3, … files; list every one.
106
+ const sitemaps: SitemapIndexEntry[] = [];
107
+ for (const { bucket, lastModified } of await listedBucketEntries(board)) {
108
+ const chunks = chunk(await buildBucketEntries(board, origin, bucket), SITEMAP_CHUNK_SIZE);
109
+ for (let i = 0; i < Math.max(chunks.length, 1); i += 1) {
110
+ sitemaps.push({
111
+ url: `${origin}/sitemap/${bucketFilename(bucket, i)}`,
112
+ ...(lastModified ? { lastModified } : {}),
113
+ });
114
+ }
115
+ }
116
+ const indexXml = renderSitemapIndex(sitemaps);
117
+
118
+ // Bucket file: every <url> keeps its own stamp.
119
+ const entries = await buildBucketEntries(board, origin, parsed.bucket);
120
+ const page = chunk(entries, SITEMAP_CHUNK_SIZE)[parsed.chunkIndex] ?? [];
121
+ const bucketXml = renderUrlset(page);
122
+ ```
123
+
124
+ `buildBucketUrls` and `listedBuckets` still return plain strings and bucket
125
+ names; they are unchanged, and a sitemap built from them carries no
126
+ `<lastmod>`.
127
+
80
128
  ## Keep the walker policy intact
81
129
 
82
- `buildBucketUrls` is the policy boundary:
130
+ `buildBucketEntries` is the policy boundary (`buildBucketUrls` is a map over
131
+ it):
83
132
 
84
133
  - Taxonomy and location pages enter the sitemap at five distinct jobs,
85
134
  `MIN_JOBS_PER_INDEXED_PAGE`.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.22.0",
2
+ "version": "4.24.0",
3
3
  "skills": [
4
4
  {
5
5
  "name": "cavuno-board-account",