@cavuno/board 4.42.0 → 4.45.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 +56 -0
  2. package/dist/{_spec-B2aizgxr.d.mts → _spec-CdNZDaaR.d.mts} +39 -0
  3. package/dist/{_spec-B2aizgxr.d.ts → _spec-CdNZDaaR.d.ts} +39 -0
  4. package/dist/bin.mjs +570 -10
  5. package/dist/{blog-BkACbXY0.d.ts → blog-ZvLJ6w1Q.d.ts} +1 -1
  6. package/dist/{blog-CYHSnNTZ.d.mts → blog-uV51b4Cg.d.mts} +1 -1
  7. package/dist/{board-DWeT9Jbl.d.ts → board-3JU14eF3.d.ts} +2 -2
  8. package/dist/{board-DK4HmSty.d.mts → board-CJw-MJpf.d.mts} +2 -2
  9. package/dist/{breadcrumbs-nTfIWzRh.d.mts → breadcrumbs-BY1UMCbL.d.mts} +2 -2
  10. package/dist/{breadcrumbs-CtKa2zPe.d.ts → breadcrumbs-CXvdv6Ry.d.ts} +2 -2
  11. package/dist/browser/cavuno-board.global.min.js +1 -1
  12. package/dist/{chunk-WSO6JN5C.mjs → chunk-DZD3DAEY.mjs} +2 -0
  13. package/dist/doctor.d.mts +1 -0
  14. package/dist/doctor.d.ts +1 -0
  15. package/dist/doctor.js +570 -10
  16. package/dist/doctor.mjs +570 -10
  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 +107 -14
  22. package/dist/index.d.ts +107 -14
  23. package/dist/index.js +129 -8
  24. package/dist/index.mjs +128 -9
  25. package/dist/{jobs-SAkNWgAB.d.ts → jobs-C7UvN_dW.d.ts} +1 -1
  26. package/dist/{jobs-C_eO-WfM.d.mts → jobs-D9ERWWda.d.mts} +1 -1
  27. package/dist/{search-Cb3Aoa4c.d.mts → search-BMSNK85o.d.mts} +1 -1
  28. package/dist/{search-CVcMFOuJ.d.ts → search-D0TFnn1x.d.ts} +1 -1
  29. package/dist/{seo-DPVud7SH.d.mts → seo-C3WmgifR.d.mts} +1 -1
  30. package/dist/{seo-DgFBQTIK.d.ts → seo-CYmVKHsu.d.ts} +1 -1
  31. package/dist/seo-files.d.mts +25 -3
  32. package/dist/seo-files.d.ts +25 -3
  33. package/dist/seo-files.js +44 -10
  34. package/dist/seo-files.mjs +44 -10
  35. package/dist/seo.d.mts +6 -6
  36. package/dist/seo.d.ts +6 -6
  37. package/dist/server.d.mts +6 -6
  38. package/dist/server.d.ts +6 -6
  39. package/dist/server.mjs +1 -1
  40. package/dist/sitemap.d.mts +6 -6
  41. package/dist/sitemap.d.ts +6 -6
  42. package/dist/sitemap.mjs +1 -1
  43. package/dist/suggest.d.mts +2 -2
  44. package/dist/suggest.d.ts +2 -2
  45. package/package.json +1 -1
  46. package/skills/cavuno-board-filters/SKILL.md +13 -0
  47. package/skills/cavuno-board-i18n/SKILL.md +10 -0
  48. package/skills/cavuno-board-post-a-job/SKILL.md +2 -1
  49. package/skills/manifest.json +1 -1
@@ -3,25 +3,54 @@ var SEO_FILE_CONTENT_TYPE = "text/plain; charset=utf-8";
3
3
  var ROBOTS_CACHE_CONTROL = "public, max-age=600, s-maxage=14400, stale-while-revalidate=86400";
4
4
  var ADS_TXT_CACHE_CONTROL = "public, max-age=3600, must-revalidate";
5
5
  var INDEXNOW_CACHE_CONTROL = "public, max-age=86400, must-revalidate";
6
+ var DEFAULT_LISTING_PATHS = {
7
+ jobs: "/jobs",
8
+ companies: "/companies",
9
+ talent: "/talent"
10
+ };
11
+ var SAFE_LISTING_ROOT = /^(?:\/[^\s/*$?#]+)+$/;
12
+ function safeListingRoot(value) {
13
+ if (typeof value !== "string") return null;
14
+ const root = value.replace(/\/+$/, "");
15
+ return SAFE_LISTING_ROOT.test(root) ? root : null;
16
+ }
17
+ function listingRoot(value, fallback) {
18
+ return safeListingRoot(value) ?? fallback;
19
+ }
20
+ var LISTING_GROUPS = ["jobs", "companies", "talent"];
21
+ function paginationRules(root) {
22
+ return [
23
+ `Disallow: ${root}?page=`,
24
+ `Disallow: ${root}*&page=`,
25
+ `Disallow: ${root}/*?page=`
26
+ ];
27
+ }
6
28
  function robotsBody(input) {
7
29
  if (input.sandbox) {
8
30
  return ["User-Agent: *", "Disallow: /", ""].join("\n");
9
31
  }
10
32
  const canonicalBase = input.canonicalBase.replace(/\/+$/, "");
33
+ const paths = input.listingPaths ?? {};
34
+ const baseRoots = LISTING_GROUPS.map(
35
+ (group) => listingRoot(paths[group], DEFAULT_LISTING_PATHS[group])
36
+ );
37
+ const seen = new Set(baseRoots);
38
+ const localeRoots = [];
39
+ for (const locale of input.localeListingPaths ?? []) {
40
+ for (const group of LISTING_GROUPS) {
41
+ const root = safeListingRoot(locale[group]);
42
+ if (root === null || seen.has(root)) continue;
43
+ seen.add(root);
44
+ localeRoots.push(root);
45
+ }
46
+ }
11
47
  return [
12
48
  "User-Agent: *",
13
49
  "Allow: /",
14
50
  "Disallow: /go/",
15
51
  "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=",
52
+ ...baseRoots.flatMap(paginationRules),
53
+ ...localeRoots.flatMap(paginationRules),
25
54
  "",
26
55
  `Sitemap: ${canonicalBase}/sitemap.xml`,
27
56
  ""
@@ -29,7 +58,12 @@ function robotsBody(input) {
29
58
  }
30
59
  function robotsResponse(seo, init) {
31
60
  return textFileResponse(
32
- robotsBody({ canonicalBase: seo.canonicalBase, sandbox: seo.sandbox }),
61
+ robotsBody({
62
+ canonicalBase: seo.canonicalBase,
63
+ sandbox: seo.sandbox,
64
+ listingPaths: seo.listingPaths,
65
+ localeListingPaths: seo.localeListingPaths
66
+ }),
33
67
  ROBOTS_CACHE_CONTROL,
34
68
  init
35
69
  );
package/dist/seo.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-CYHSnNTZ.mjs';
2
- import { e as JsonLdObject } from './breadcrumbs-nTfIWzRh.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-nTfIWzRh.mjs';
4
- import './_spec-B2aizgxr.mjs';
5
- import './board-DK4HmSty.mjs';
6
- import './jobs-C_eO-WfM.mjs';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-uV51b4Cg.mjs';
2
+ import { e as JsonLdObject } from './breadcrumbs-BY1UMCbL.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-BY1UMCbL.mjs';
4
+ import './_spec-CdNZDaaR.mjs';
5
+ import './board-CJw-MJpf.mjs';
6
+ import './jobs-D9ERWWda.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-BkACbXY0.js';
2
- import { e as JsonLdObject } from './breadcrumbs-CtKa2zPe.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-CtKa2zPe.js';
4
- import './_spec-B2aizgxr.js';
5
- import './board-DWeT9Jbl.js';
6
- import './jobs-SAkNWgAB.js';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-ZvLJ6w1Q.js';
2
+ import { e as JsonLdObject } from './breadcrumbs-CXvdv6Ry.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-CXvdv6Ry.js';
4
+ import './_spec-CdNZDaaR.js';
5
+ import './board-3JU14eF3.js';
6
+ import './jobs-C7UvN_dW.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-B2aizgxr.mjs';
3
- import './search-Cb3Aoa4c.mjs';
4
- import './board-DK4HmSty.mjs';
5
- import './jobs-C_eO-WfM.mjs';
6
- import './seo-DPVud7SH.mjs';
7
- import './blog-CYHSnNTZ.mjs';
2
+ import './_spec-CdNZDaaR.mjs';
3
+ import './search-BMSNK85o.mjs';
4
+ import './jobs-D9ERWWda.mjs';
5
+ import './board-CJw-MJpf.mjs';
6
+ import './seo-C3WmgifR.mjs';
7
+ import './blog-uV51b4Cg.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-B2aizgxr.js';
3
- import './search-CVcMFOuJ.js';
4
- import './board-DWeT9Jbl.js';
5
- import './jobs-SAkNWgAB.js';
6
- import './seo-DgFBQTIK.js';
7
- import './blog-BkACbXY0.js';
2
+ import './_spec-CdNZDaaR.js';
3
+ import './search-D0TFnn1x.js';
4
+ import './jobs-C7UvN_dW.js';
5
+ import './board-3JU14eF3.js';
6
+ import './seo-CYmVKHsu.js';
7
+ import './blog-ZvLJ6w1Q.js';
8
8
 
9
9
  /**
10
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-Z4ALWIGS.mjs";
5
5
  import {
6
6
  isUnauthorized
7
- } from "./chunk-WSO6JN5C.mjs";
7
+ } from "./chunk-DZD3DAEY.mjs";
8
8
 
9
9
  // src/server/cookie.ts
10
10
  var COOKIE_ATTRIBUTES = "Path=/; HttpOnly; Secure; SameSite=Lax";
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-B2aizgxr.mjs';
3
- import './search-Cb3Aoa4c.mjs';
4
- import './board-DK4HmSty.mjs';
5
- import './jobs-C_eO-WfM.mjs';
6
- import './seo-DPVud7SH.mjs';
7
- import './blog-CYHSnNTZ.mjs';
2
+ import './_spec-CdNZDaaR.mjs';
3
+ import './search-BMSNK85o.mjs';
4
+ import './jobs-D9ERWWda.mjs';
5
+ import './board-CJw-MJpf.mjs';
6
+ import './seo-C3WmgifR.mjs';
7
+ import './blog-uV51b4Cg.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-B2aizgxr.js';
3
- import './search-CVcMFOuJ.js';
4
- import './board-DWeT9Jbl.js';
5
- import './jobs-SAkNWgAB.js';
6
- import './seo-DgFBQTIK.js';
7
- import './blog-BkACbXY0.js';
2
+ import './_spec-CdNZDaaR.js';
3
+ import './search-D0TFnn1x.js';
4
+ import './jobs-C7UvN_dW.js';
5
+ import './board-3JU14eF3.js';
6
+ import './seo-CYmVKHsu.js';
7
+ import './blog-ZvLJ6w1Q.js';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-DLSO6XXY.mjs";
4
4
  import {
5
5
  isNotFound
6
- } from "./chunk-WSO6JN5C.mjs";
6
+ } from "./chunk-DZD3DAEY.mjs";
7
7
  import {
8
8
  BOARD_PATHS,
9
9
  blogAuthorPath,
@@ -1,5 +1,5 @@
1
- import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-Cb3Aoa4c.mjs';
2
- import './_spec-B2aizgxr.mjs';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-BMSNK85o.mjs';
2
+ import './_spec-CdNZDaaR.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-CVcMFOuJ.js';
2
- import './_spec-B2aizgxr.js';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-D0TFnn1x.js';
2
+ import './_spec-CdNZDaaR.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.42.0",
3
+ "version": "4.45.0",
4
4
  "description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -150,6 +150,19 @@ const { items } = await board.search.suggest({
150
150
  The host router owns URL serialization and saved-filter persistence.
151
151
  Locations come from `board.taxonomy.places` rather than a static filter export.
152
152
 
153
+ A talent directory's location filter lists the places where the board's
154
+ candidates live instead, from `board.talent.places.list()`, with the count the
155
+ viewer can see. Pass `q` to search it for a location box (same matching as
156
+ `board.taxonomy.places.list`'s `q`). Pass the chosen `slug` as the directory's
157
+ `place`:
158
+
159
+ ```ts snippet
160
+ const { data: talentPlaces } = await board.talent.places.list({ limit: 50 });
161
+ const nearby = await board.talent.list({ place: talentPlaces[0]?.slug ?? undefined });
162
+
163
+ void nearby.data;
164
+ ```
165
+
153
166
  ## Filter jobs by a job custom field
154
167
 
155
168
  The operator's job custom fields arrive as definitions on
@@ -44,6 +44,16 @@ Use the installed framework and i18n guidance for routing, SSR locale detection,
44
44
 
45
45
  A compile-time i18n system can replace the seam's backing source. Keep the seam provider-free unless the chosen framework integration itself requires a provider.
46
46
 
47
+ ## Renaming a URL word
48
+
49
+ When a translated URL segment changes (for example `vacatures` to `banen`), links that used the old word must keep working. List every retired word in `src/url-words-previous.json`, keyed by locale and canonical segment:
50
+
51
+ ```json
52
+ { "nl": { "jobs": ["vacatures"] } }
53
+ ```
54
+
55
+ Starters that read this file redirect a request that uses a retired word to the current word with one 308; the SDK itself does not perform the redirect. List each word under one segment only, and never list a word that is in current use. On boards built with the Cavuno builder, the hosting platform maintains this file at every save. Do not delete entries: an old link stops working the moment its word leaves the list.
56
+
47
57
  ## Own the five obligations
48
58
 
49
59
  The SDK formats amounts, units, and relative dates with `Intl` and returns
@@ -168,7 +168,7 @@ The checkout value is a URL for a host-owned full-page redirect. Payment publica
168
168
 
169
169
  ## Verified existing credit
170
170
 
171
- Email verification protects billing ownership. Send verification first, then exchange the token for options; a selected option becomes `selectedBilling`.
171
+ Email verification protects billing ownership. Send verification first, then exchange the token for options; a selected option becomes `selectedBilling`, and the same token goes with it as `billingVerificationToken`. The token expires after an hour; verify again if it has.
172
172
 
173
173
  ```ts snippet
174
174
  await board.jobPosting.sendBillingVerification({ email });
@@ -190,6 +190,7 @@ if (option) {
190
190
  id: option.id,
191
191
  planId: option.planId,
192
192
  },
193
+ billingVerificationToken: verificationToken,
193
194
  });
194
195
  }
195
196
  ```
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.42.0",
2
+ "version": "4.45.0",
3
3
  "skills": [
4
4
  {
5
5
  "name": "cavuno-board-account",