@cavuno/board 3.0.0 → 3.2.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 (64) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +11 -0
  3. package/dist/blog-DGBHmExV.d.mts +29 -0
  4. package/dist/blog-iV9XEIGf.d.ts +29 -0
  5. package/dist/{salaries-ChSqDBAM.d.mts → board-BJbXd_9_.d.mts} +14 -27
  6. package/dist/{salaries-BahBpxWT.d.ts → board-JhdUWIoq.d.ts} +14 -27
  7. package/dist/breadcrumbs-1hMjcsqA.d.mts +171 -0
  8. package/dist/breadcrumbs-DexU07TT.d.ts +171 -0
  9. package/dist/chunk-2ETP5UH4.mjs +271 -0
  10. package/dist/chunk-DLSO6XXY.mjs +33 -0
  11. package/dist/chunk-IJCJ26SQ.mjs +596 -0
  12. package/dist/chunk-L7ZOYWHW.mjs +98 -0
  13. package/dist/chunk-LUGJWOT7.mjs +96 -0
  14. package/dist/chunk-NXY3OWGF.mjs +1060 -0
  15. package/dist/chunk-STE77MAT.mjs +844 -0
  16. package/dist/filters.mjs +7 -668
  17. package/dist/format.d.mts +2 -1
  18. package/dist/format.d.ts +2 -1
  19. package/dist/format.js +592 -523
  20. package/dist/format.mjs +19 -680
  21. package/dist/go.mjs +4 -29
  22. package/dist/index.d.mts +5 -4
  23. package/dist/index.d.ts +5 -4
  24. package/dist/index.js +1 -1
  25. package/dist/index.mjs +22 -278
  26. package/dist/paths.mjs +20 -77
  27. package/dist/route-contract.mjs +30 -1079
  28. package/dist/seo.d.mts +14 -171
  29. package/dist/seo.d.ts +14 -171
  30. package/dist/seo.js +1 -1
  31. package/dist/seo.mjs +24 -1399
  32. package/dist/server.d.mts +2 -2
  33. package/dist/server.d.ts +2 -2
  34. package/dist/server.mjs +5 -31
  35. package/dist/sitemap.d.mts +2 -2
  36. package/dist/sitemap.d.ts +2 -2
  37. package/dist/sitemap.mjs +20 -96
  38. package/dist/well-known.mjs +4 -421
  39. package/package.json +6 -3
  40. package/skills/cavuno-board-account/SKILL.md +4 -0
  41. package/skills/cavuno-board-api-client/SKILL.md +4 -0
  42. package/skills/cavuno-board-applications/SKILL.md +4 -0
  43. package/skills/cavuno-board-auth/SKILL.md +4 -0
  44. package/skills/cavuno-board-blog/SKILL.md +4 -0
  45. package/skills/cavuno-board-companies/SKILL.md +4 -0
  46. package/skills/cavuno-board-errors/SKILL.md +4 -0
  47. package/skills/cavuno-board-filters/SKILL.md +4 -0
  48. package/skills/cavuno-board-format/SKILL.md +4 -0
  49. package/skills/cavuno-board-i18n/SKILL.md +4 -0
  50. package/skills/cavuno-board-job-alerts/SKILL.md +4 -0
  51. package/skills/cavuno-board-jobs/SKILL.md +4 -0
  52. package/skills/cavuno-board-messaging/SKILL.md +4 -0
  53. package/skills/cavuno-board-paywall/SKILL.md +4 -0
  54. package/skills/cavuno-board-post-a-job/SKILL.md +4 -0
  55. package/skills/cavuno-board-salaries/SKILL.md +4 -0
  56. package/skills/cavuno-board-search-suggestions/SKILL.md +4 -0
  57. package/skills/cavuno-board-seo/SKILL.md +4 -0
  58. package/skills/cavuno-board-server-sessions/SKILL.md +4 -0
  59. package/skills/cavuno-board-setup/SKILL.md +4 -0
  60. package/skills/cavuno-board-sitemap/SKILL.md +4 -0
  61. package/skills/cavuno-board-smoke-test/SKILL.md +4 -0
  62. package/skills/manifest.json +1 -1
  63. package/dist/board-NE98PlwN.d.ts +0 -16
  64. package/dist/board-muu8BI8P.d.mts +0 -16
package/CHANGELOG.md CHANGED
@@ -3,6 +3,27 @@
3
3
  This changelog records changes that affect Board API compatibility, exported
4
4
  types, runtime behavior, or supported integration patterns.
5
5
 
6
+ ## 3.2.0 — 2026-08-03
7
+
8
+ - Added `formatSalaryStatUsd`, `formatSalaryStatRange`, `normalizeWebsiteUrl`,
9
+ and `buildJobBreadcrumbs` to `@cavuno/board/format`. These presentation
10
+ helpers previously required importing `@cavuno/board/seo`, which pulled the
11
+ structured-data builders into client bundles; frontends can now keep the SEO
12
+ entry server-only. The `@cavuno/board/seo` exports are unchanged.
13
+ - Split the ESM builds of the isomorphic entries into shared chunks, so a
14
+ selective import no longer carries unrelated builders. CommonJS output is
15
+ unchanged.
16
+ - `listingHead` accepts an optional `language` and groups the result count for
17
+ that locale in the title and meta description (`1,225 Jobs` / `1.225 Jobs`),
18
+ matching how listing bodies render the same number. Callers that omit
19
+ `language` keep byte-identical output.
20
+
21
+ ## 3.1.0 — 2026-08-03
22
+
23
+ - Added direct skills.sh installation guidance and repository grouping for all
24
+ 22 Cavuno Board SDK skills.
25
+ - Linked every independently installable skill to the Cavuno SDK documentation.
26
+
6
27
  ## 3.0.0 — 2026-08-03
7
28
 
8
29
  - Removed runtime theme data from `board.context()` and removed the
package/README.md CHANGED
@@ -19,6 +19,17 @@ other compatible coding agents. It teaches them how to wire a board correctly
19
19
  auth and session ownership, pagination, gating, error handling, and a
20
20
  runtime smoke test:
21
21
 
22
+ Install the latest skills directly from the public SDK repository:
23
+
24
+ ```bash
25
+ npx skills add wollemiahq/cavuno-sdk --skill cavuno-board-setup
26
+ # Or install the complete Cavuno skill set:
27
+ npx skills add wollemiahq/cavuno-sdk --skill '*'
28
+ ```
29
+
30
+ For skills matched exactly to an installed SDK version, copy them from the
31
+ package instead:
32
+
22
33
  ```bash
23
34
  npm install @cavuno/board # or: pnpm add / yarn add / bun add
24
35
  npx @cavuno/board setup # copies version-matched Agent Skills
@@ -0,0 +1,29 @@
1
+ import { S as Schemas } from './_spec-nkWAraS0.mjs';
2
+
3
+ /** Author shape embedded on posts (no `object` discriminator). */
4
+ type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
5
+ /** Tag shape embedded on posts (no `object` discriminator). */
6
+ type BlogTagEmbed = Schemas['PublicBlogTagEmbed'];
7
+ type PublicBlogAuthor = Schemas['PublicBlogAuthor'];
8
+ type PublicBlogTag = Schemas['PublicBlogTag'];
9
+ type PublicBlogPostSummary = Schemas['PublicBlogPostSummary'];
10
+ /** Detail shape — `html` appears on the single read only, never on summaries. */
11
+ type PublicBlogPost = Schemas['PublicBlogPost'];
12
+ /** Previous (older) + next (newer) posts for the detail prev/next nav. */
13
+ type PublicBlogAdjacentPosts = Schemas['PublicBlogAdjacentPosts'];
14
+ type BlogPostsListQuery = {
15
+ cursor?: string;
16
+ /** 1–100. */
17
+ limit?: number;
18
+ tagSlug?: string;
19
+ authorSlug?: string;
20
+ /** Opt-in only: pass `'true'` to restrict to featured posts. */
21
+ featured?: 'true';
22
+ };
23
+ type BlogSimilarQuery = {
24
+ /** 1–20; default 6. */
25
+ limit?: number;
26
+ };
27
+ type BlogSearchBody = Schemas['PublicBlogSearchBody'];
28
+
29
+ export type { BlogAuthorEmbed as B, PublicBlogPostSummary as P, BlogPostsListQuery as a, BlogSimilarQuery as b, BlogSearchBody as c, BlogTagEmbed as d, PublicBlogAdjacentPosts as e, PublicBlogAuthor as f, PublicBlogPost as g, PublicBlogTag as h };
@@ -0,0 +1,29 @@
1
+ import { S as Schemas } from './_spec-nkWAraS0.js';
2
+
3
+ /** Author shape embedded on posts (no `object` discriminator). */
4
+ type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
5
+ /** Tag shape embedded on posts (no `object` discriminator). */
6
+ type BlogTagEmbed = Schemas['PublicBlogTagEmbed'];
7
+ type PublicBlogAuthor = Schemas['PublicBlogAuthor'];
8
+ type PublicBlogTag = Schemas['PublicBlogTag'];
9
+ type PublicBlogPostSummary = Schemas['PublicBlogPostSummary'];
10
+ /** Detail shape — `html` appears on the single read only, never on summaries. */
11
+ type PublicBlogPost = Schemas['PublicBlogPost'];
12
+ /** Previous (older) + next (newer) posts for the detail prev/next nav. */
13
+ type PublicBlogAdjacentPosts = Schemas['PublicBlogAdjacentPosts'];
14
+ type BlogPostsListQuery = {
15
+ cursor?: string;
16
+ /** 1–100. */
17
+ limit?: number;
18
+ tagSlug?: string;
19
+ authorSlug?: string;
20
+ /** Opt-in only: pass `'true'` to restrict to featured posts. */
21
+ featured?: 'true';
22
+ };
23
+ type BlogSimilarQuery = {
24
+ /** 1–20; default 6. */
25
+ limit?: number;
26
+ };
27
+ type BlogSearchBody = Schemas['PublicBlogSearchBody'];
28
+
29
+ export type { BlogAuthorEmbed as B, PublicBlogPostSummary as P, BlogPostsListQuery as a, BlogSimilarQuery as b, BlogSearchBody as c, BlogTagEmbed as d, PublicBlogAdjacentPosts as e, PublicBlogAuthor as f, PublicBlogPost as g, PublicBlogTag as h };
@@ -1,32 +1,6 @@
1
1
  import { S as Schemas } from './_spec-nkWAraS0.mjs';
2
2
  import { L as ListEnvelope, m as RelatedSearch } from './jobs-lVvKCBCU.mjs';
3
3
 
4
- /** Author shape embedded on posts (no `object` discriminator). */
5
- type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
6
- /** Tag shape embedded on posts (no `object` discriminator). */
7
- type BlogTagEmbed = Schemas['PublicBlogTagEmbed'];
8
- type PublicBlogAuthor = Schemas['PublicBlogAuthor'];
9
- type PublicBlogTag = Schemas['PublicBlogTag'];
10
- type PublicBlogPostSummary = Schemas['PublicBlogPostSummary'];
11
- /** Detail shape — `html` appears on the single read only, never on summaries. */
12
- type PublicBlogPost = Schemas['PublicBlogPost'];
13
- /** Previous (older) + next (newer) posts for the detail prev/next nav. */
14
- type PublicBlogAdjacentPosts = Schemas['PublicBlogAdjacentPosts'];
15
- type BlogPostsListQuery = {
16
- cursor?: string;
17
- /** 1–100. */
18
- limit?: number;
19
- tagSlug?: string;
20
- authorSlug?: string;
21
- /** Opt-in only: pass `'true'` to restrict to featured posts. */
22
- featured?: 'true';
23
- };
24
- type BlogSimilarQuery = {
25
- /** 1–20; default 6. */
26
- limit?: number;
27
- };
28
- type BlogSearchBody = Schemas['PublicBlogSearchBody'];
29
-
30
4
  type PublicCompany = Schemas['CompanyPublic'];
31
5
  /** A market (sector) a company operates in — name + its source slug. */
32
6
  type CompanyMarketRef = Schemas['CompanyMarketRef'];
@@ -114,4 +88,17 @@ type SalaryDetailQuery = {
114
88
  locale?: string;
115
89
  };
116
90
 
117
- export type { SkillLocationSalary as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBlogPostSummary as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanySalary as a, CompaniesListQuery as b, CompanyListEnvelope as c, CompaniesSearchBody as d, CompanyJobsListQuery as e, CompanySimilarQuery as f, CompanyMarketsListQuery as g, SalaryDetailQuery as h, BlogPostsListQuery as i, BlogSimilarQuery as j, BlogSearchBody as k, BlogTagEmbed as l, CompanyMarket as m, CompanyMarketRef as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBlogAdjacentPosts as q, PublicBlogAuthor as r, PublicBlogPost as s, PublicBlogTag as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
91
+ type PublicBoard = Schemas['PublicBoardContext'];
92
+ type PublicBoardFeatures = PublicBoard['features'];
93
+ type PublicBoardAnalytics = PublicBoard['analytics'];
94
+ /**
95
+ * An operator-defined custom job-field definition. Board-wide;
96
+ * use it to render and localize a job's opaque `customFieldValues` (resolve
97
+ * option `key`s → labels, honour field `type` and display order). Shared with
98
+ * the Operator API's custom-field surface (one canonical schema).
99
+ */
100
+ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
101
+ type CustomFieldType = CustomFieldDefinition['type'];
102
+ type CustomFieldOption = Schemas['CustomFieldOption'];
103
+
104
+ export type { TitleLocationsIndex as A, CustomFieldDefinition as C, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CustomFieldOption as l, CustomFieldType as m, LocationSkillsIndex as n, LocationTitlesIndex as o, PublicBoardAnalytics as p, PublicBoardFeatures as q, PublicCompany as r, PublicCompanyDetail as s, SalaryCompany as t, SalaryLocation as u, SalarySkill as v, SalaryTitle as w, SkillLocationSalary as x, SkillLocationsIndex as y, TitleLocationSalary as z };
@@ -1,32 +1,6 @@
1
1
  import { S as Schemas } from './_spec-nkWAraS0.js';
2
2
  import { L as ListEnvelope, m as RelatedSearch } from './jobs-BiEvL9d7.js';
3
3
 
4
- /** Author shape embedded on posts (no `object` discriminator). */
5
- type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
6
- /** Tag shape embedded on posts (no `object` discriminator). */
7
- type BlogTagEmbed = Schemas['PublicBlogTagEmbed'];
8
- type PublicBlogAuthor = Schemas['PublicBlogAuthor'];
9
- type PublicBlogTag = Schemas['PublicBlogTag'];
10
- type PublicBlogPostSummary = Schemas['PublicBlogPostSummary'];
11
- /** Detail shape — `html` appears on the single read only, never on summaries. */
12
- type PublicBlogPost = Schemas['PublicBlogPost'];
13
- /** Previous (older) + next (newer) posts for the detail prev/next nav. */
14
- type PublicBlogAdjacentPosts = Schemas['PublicBlogAdjacentPosts'];
15
- type BlogPostsListQuery = {
16
- cursor?: string;
17
- /** 1–100. */
18
- limit?: number;
19
- tagSlug?: string;
20
- authorSlug?: string;
21
- /** Opt-in only: pass `'true'` to restrict to featured posts. */
22
- featured?: 'true';
23
- };
24
- type BlogSimilarQuery = {
25
- /** 1–20; default 6. */
26
- limit?: number;
27
- };
28
- type BlogSearchBody = Schemas['PublicBlogSearchBody'];
29
-
30
4
  type PublicCompany = Schemas['CompanyPublic'];
31
5
  /** A market (sector) a company operates in — name + its source slug. */
32
6
  type CompanyMarketRef = Schemas['CompanyMarketRef'];
@@ -114,4 +88,17 @@ type SalaryDetailQuery = {
114
88
  locale?: string;
115
89
  };
116
90
 
117
- export type { SkillLocationSalary as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBlogPostSummary as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanySalary as a, CompaniesListQuery as b, CompanyListEnvelope as c, CompaniesSearchBody as d, CompanyJobsListQuery as e, CompanySimilarQuery as f, CompanyMarketsListQuery as g, SalaryDetailQuery as h, BlogPostsListQuery as i, BlogSimilarQuery as j, BlogSearchBody as k, BlogTagEmbed as l, CompanyMarket as m, CompanyMarketRef as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBlogAdjacentPosts as q, PublicBlogAuthor as r, PublicBlogPost as s, PublicBlogTag as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
91
+ type PublicBoard = Schemas['PublicBoardContext'];
92
+ type PublicBoardFeatures = PublicBoard['features'];
93
+ type PublicBoardAnalytics = PublicBoard['analytics'];
94
+ /**
95
+ * An operator-defined custom job-field definition. Board-wide;
96
+ * use it to render and localize a job's opaque `customFieldValues` (resolve
97
+ * option `key`s → labels, honour field `type` and display order). Shared with
98
+ * the Operator API's custom-field surface (one canonical schema).
99
+ */
100
+ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
101
+ type CustomFieldType = CustomFieldDefinition['type'];
102
+ type CustomFieldOption = Schemas['CustomFieldOption'];
103
+
104
+ export type { TitleLocationsIndex as A, CustomFieldDefinition as C, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CustomFieldOption as l, CustomFieldType as m, LocationSkillsIndex as n, LocationTitlesIndex as o, PublicBoardAnalytics as p, PublicBoardFeatures as q, PublicCompany as r, PublicCompanyDetail as s, SalaryCompany as t, SalaryLocation as u, SalarySkill as v, SalaryTitle as w, SkillLocationSalary as x, SkillLocationsIndex as y, TitleLocationSalary as z };
@@ -0,0 +1,171 @@
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-BJbXd_9_.mjs';
2
+ import { B as BoardLabelOverrides } from './ui-copy-CCkz6CVF.mjs';
3
+ import { P as PublicJob } from './jobs-lVvKCBCU.mjs';
4
+
5
+ /**
6
+ * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
7
+ * types, transcribed field-by-field from the hosted board's generator
8
+ * (the hosted board implementation + `job-posting-location-json-ld.ts`) and
9
+ * tested against the hosted behavior.
10
+ *
11
+ * JSON-LD structure is locale-neutral per schema.org — no board-language
12
+ * parameter here; the only display strings are wire values passed through.
13
+ *
14
+ * Named exclusions (hosted behaviours with no wire twin, recorded in the
15
+ * public API contract):
16
+ * - `board.companyLegalName` — hosted falls back to it for the
17
+ * organization name between `company.name` and `board.name`; the wire
18
+ * board context does not expose it.
19
+ * - `board.companyWebsiteUrl` — hosted falls back to it for `sameAs` when
20
+ * the company has no website; not on the wire.
21
+ * - the hosted `job.place`/`locationLabel` jobLocation fallback (used when
22
+ * a job has no office locations) — the wire `PublicJob` carries no
23
+ * resolved place geo, only `officeLocations`.
24
+ */
25
+
26
+ type JsonLdObject = Record<string, unknown>;
27
+ /** The only board fields JSON-LD needs — keeps callers' shapes flexible. */
28
+ type JsonLdBoard = Pick<PublicBoard, 'name' | 'logoUrl'>;
29
+ /**
30
+ * Worldwide-remote jobs must still emit `applicantLocationRequirements`
31
+ * next to TELECOMMUTE (Google requires a location signal), so the hosted
32
+ * board — and this transcription — lists every country it recognises.
33
+ *
34
+ * This is the hosted board's exact country catalog: sorted by English common
35
+ * name, includes `XK` (Kosovo), and excludes `KP` (North Korea). tested
36
+ * against the hosted list so the two cannot drift.
37
+ */
38
+ declare const ALL_COUNTRY_CODES: readonly ["AF", "AX", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BV", "BR", "IO", "VG", "BN", "BG", "BF", "BI", "KH", "CM", "CA", "CV", "BQ", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CK", "CR", "HR", "CU", "CW", "CY", "CZ", "DK", "DJ", "DM", "DO", "CD", "EC", "EG", "SV", "GQ", "ER", "EE", "SZ", "ET", "FK", "FO", "FJ", "FI", "FR", "GF", "PF", "TF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GP", "GU", "GT", "GG", "GN", "GW", "GY", "HT", "HM", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "XK", "KW", "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "MM", "NA", "NR", "NP", "NL", "NC", "NZ", "NI", "NE", "NG", "NU", "NF", "MK", "MP", "NO", "OM", "PK", "PW", "PS", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RE", "RO", "RU", "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SX", "SK", "SI", "SB", "SO", "ZA", "GS", "KR", "SS", "ES", "LK", "SD", "SR", "SJ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UM", "VI", "UY", "UZ", "VU", "VA", "VE", "VN", "WF", "EH", "YE", "ZM", "ZW"];
39
+ /**
40
+ * Build the Google for Jobs `JobPosting` JSON-LD object for a job detail
41
+ * page, or `null` when nothing renderable remains after pruning. Embed the
42
+ * result in a `<script type="application/ld+json">` tag.
43
+ */
44
+ declare function createJobPostingJsonLd({ job, board, shareUrl, }: {
45
+ job: PublicJob;
46
+ board: JsonLdBoard;
47
+ shareUrl: string;
48
+ }): JsonLdObject | null;
49
+ /**
50
+ * Prefix `https://` onto scheme-less company websites; `null` for
51
+ * blank input (hosted shape — a whitespace-only website never becomes
52
+ * a bare `https://` `sameAs`).
53
+ */
54
+ declare function normalizeWebsiteUrl(website: string): string | null;
55
+
56
+ /**
57
+ * Compact USD amount in the board language (`$90K`, de: `90.000 $`) — the
58
+ * hosted salary-page money formatter. USD-hardcoded (hosted quirk); the
59
+ * locale drives digits, grouping, and symbol placement only.
60
+ */
61
+ declare function formatUsd(locale: string, value: number): string;
62
+ /** `formatUsd(min) – formatUsd(max)` with the hosted spaced en dash. */
63
+ declare function formatRange(locale: string, min: number, max: number): string;
64
+ /**
65
+ * Seniority display label. Precedence (hosted shape): owner override >
66
+ * board-language lexicon (en = the English source labels) > title-case
67
+ * fallback for an unknown key.
68
+ */
69
+ declare function formatSeniority(locale: string, value: string, overrides?: Record<string, string>): string;
70
+ /** The canonical seniority ladder order the hosted salary pages sort by. */
71
+ declare const SENIORITY_ORDER: readonly ["entry_level", "associate", "mid_level", "senior", "lead", "principal", "director", "executive"];
72
+ /** Sort rows by `SENIORITY_ORDER` (unknown keys sink to the end). Non-mutating. */
73
+ declare function sortBySeniority<T extends {
74
+ seniority: string;
75
+ }>(items: T[]): T[];
76
+ interface FaqItem {
77
+ q: string;
78
+ a: string;
79
+ }
80
+ /**
81
+ * A templated salary FAQ (interim — see the module doc). The sentences are
82
+ * English; the embedded range is board-language-formatted via `formatRange`
83
+ * (the only part hosted localizes). Empty when there is no overall figure.
84
+ */
85
+ declare function buildSalaryFaq(locale: string, label: string, overall: {
86
+ avgMin: number;
87
+ avgMax: number;
88
+ jobCount: number;
89
+ } | null): FaqItem[];
90
+ /** An `ItemList` for a salary index page (the listing's items + their URLs). */
91
+ declare function itemListJsonLd(items: {
92
+ name: string;
93
+ url: string;
94
+ }[]): JsonLdObject | null;
95
+ /** A `FAQPage` from `buildSalaryFaq` items (or any `{q,a}` list). */
96
+ declare function faqJsonLd(faqs: FaqItem[]): JsonLdObject | null;
97
+ /**
98
+ * `Occupation` for a job-title salary page. Per-seniority distribution
99
+ * names embed the board-language seniority label (`formatSeniority`).
100
+ */
101
+ declare function titleSalaryJsonLd(locale: string, d: TitleSalaryDetail): JsonLdObject | null;
102
+ /** `Occupation` for a skill salary page (overall distribution + median). */
103
+ declare function skillSalaryJsonLd(d: SkillSalaryDetail): JsonLdObject | null;
104
+ /**
105
+ * `Occupation` for a location salary page. City-level pages only (the
106
+ * hosted page gates on city/locality); `null` otherwise.
107
+ */
108
+ declare function locationSalaryJsonLd(d: LocationSalaryDetail): JsonLdObject | null;
109
+ /**
110
+ * Cross-axis (title×location / skill×location) `Occupation` JSON-LD. Takes
111
+ * primitives to stay decoupled from the two cross-axis detail wire types.
112
+ */
113
+ declare function crossAxisSalaryJsonLd(locale: string, args: {
114
+ name: string;
115
+ placeName: string;
116
+ countryCode: string;
117
+ overall: {
118
+ avgMin: number;
119
+ avgMax: number;
120
+ p25Min: number | null;
121
+ p75Max: number | null;
122
+ } | null;
123
+ bySeniority: {
124
+ seniority: string;
125
+ avgSalaryMin: number;
126
+ avgSalaryMax: number;
127
+ }[];
128
+ currency: string;
129
+ }): JsonLdObject | null;
130
+ /**
131
+ * `OccupationAggregationByEmployer` for a company's salary overview —
132
+ * mirrors the hosted company-salary page's Google-salary structured data
133
+ * (base + per-seniority distributions, the board median/IQR baseline as
134
+ * the aggregate stats).
135
+ */
136
+ declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdObject | null;
137
+ /** `Occupation` for one job category at a company (the hosted category page). */
138
+ declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
139
+
140
+ interface BreadcrumbItemInput {
141
+ label: string | null | undefined;
142
+ href?: string | null;
143
+ }
144
+ /**
145
+ * Build a `BreadcrumbList`, hosted semantics: labels are trimmed and empty
146
+ * items dropped; fewer than 2 surviving items → `null` (a single crumb is
147
+ * not a trail); the current page (no `href`) omits `item` per schema.org.
148
+ * Relative hrefs resolve against `options.origin`; without an origin a
149
+ * relative item is omitted (never emit a relative `item` URL).
150
+ */
151
+ declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
152
+ origin?: string | null;
153
+ }): JsonLdObject | null;
154
+ /**
155
+ * Home › Jobs › [country › region › city] › primaryCategory › Title.
156
+ * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
157
+ * the category crumb nests under the most-specific place when present
158
+ * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
159
+ * crumb (the job title) carries no `path` — the current page. Mirrors
160
+ * page.tsx:336-367.
161
+ *
162
+ * The Home/Jobs crumb names resolve from the copy catalog per board
163
+ * language ⊕ operator overrides; omitting `language` keeps the
164
+ * English source, so existing call sites render unchanged.
165
+ */
166
+ declare function buildJobBreadcrumbs(job: PublicJob, language?: string, labels?: BoardLabelOverrides): Array<{
167
+ name: string;
168
+ path?: string;
169
+ }>;
170
+
171
+ export { ALL_COUNTRY_CODES as A, type BreadcrumbItemInput as B, type FaqItem as F, type JsonLdObject as J, SENIORITY_ORDER as S, formatUsd as a, buildJobBreadcrumbs as b, type JsonLdBoard as c, buildSalaryFaq as d, companyCategorySalaryJsonLd as e, formatRange as f, companySalaryJsonLd as g, createBreadcrumbJsonLd as h, createJobPostingJsonLd as i, crossAxisSalaryJsonLd as j, faqJsonLd as k, formatSeniority as l, itemListJsonLd as m, normalizeWebsiteUrl as n, locationSalaryJsonLd as o, sortBySeniority as p, skillSalaryJsonLd as s, titleSalaryJsonLd as t };
@@ -0,0 +1,171 @@
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-JhdUWIoq.js';
2
+ import { B as BoardLabelOverrides } from './ui-copy-CCkz6CVF.js';
3
+ import { P as PublicJob } from './jobs-BiEvL9d7.js';
4
+
5
+ /**
6
+ * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
7
+ * types, transcribed field-by-field from the hosted board's generator
8
+ * (the hosted board implementation + `job-posting-location-json-ld.ts`) and
9
+ * tested against the hosted behavior.
10
+ *
11
+ * JSON-LD structure is locale-neutral per schema.org — no board-language
12
+ * parameter here; the only display strings are wire values passed through.
13
+ *
14
+ * Named exclusions (hosted behaviours with no wire twin, recorded in the
15
+ * public API contract):
16
+ * - `board.companyLegalName` — hosted falls back to it for the
17
+ * organization name between `company.name` and `board.name`; the wire
18
+ * board context does not expose it.
19
+ * - `board.companyWebsiteUrl` — hosted falls back to it for `sameAs` when
20
+ * the company has no website; not on the wire.
21
+ * - the hosted `job.place`/`locationLabel` jobLocation fallback (used when
22
+ * a job has no office locations) — the wire `PublicJob` carries no
23
+ * resolved place geo, only `officeLocations`.
24
+ */
25
+
26
+ type JsonLdObject = Record<string, unknown>;
27
+ /** The only board fields JSON-LD needs — keeps callers' shapes flexible. */
28
+ type JsonLdBoard = Pick<PublicBoard, 'name' | 'logoUrl'>;
29
+ /**
30
+ * Worldwide-remote jobs must still emit `applicantLocationRequirements`
31
+ * next to TELECOMMUTE (Google requires a location signal), so the hosted
32
+ * board — and this transcription — lists every country it recognises.
33
+ *
34
+ * This is the hosted board's exact country catalog: sorted by English common
35
+ * name, includes `XK` (Kosovo), and excludes `KP` (North Korea). tested
36
+ * against the hosted list so the two cannot drift.
37
+ */
38
+ declare const ALL_COUNTRY_CODES: readonly ["AF", "AX", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BV", "BR", "IO", "VG", "BN", "BG", "BF", "BI", "KH", "CM", "CA", "CV", "BQ", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CK", "CR", "HR", "CU", "CW", "CY", "CZ", "DK", "DJ", "DM", "DO", "CD", "EC", "EG", "SV", "GQ", "ER", "EE", "SZ", "ET", "FK", "FO", "FJ", "FI", "FR", "GF", "PF", "TF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GP", "GU", "GT", "GG", "GN", "GW", "GY", "HT", "HM", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IM", "IL", "IT", "CI", "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "XK", "KW", "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS", "MA", "MZ", "MM", "NA", "NR", "NP", "NL", "NC", "NZ", "NI", "NE", "NG", "NU", "NF", "MK", "MP", "NO", "OM", "PK", "PW", "PS", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "CG", "RE", "RO", "RU", "RW", "BL", "SH", "KN", "LC", "MF", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG", "SX", "SK", "SI", "SB", "SO", "ZA", "GS", "KR", "SS", "ES", "LK", "SD", "SR", "SJ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UM", "VI", "UY", "UZ", "VU", "VA", "VE", "VN", "WF", "EH", "YE", "ZM", "ZW"];
39
+ /**
40
+ * Build the Google for Jobs `JobPosting` JSON-LD object for a job detail
41
+ * page, or `null` when nothing renderable remains after pruning. Embed the
42
+ * result in a `<script type="application/ld+json">` tag.
43
+ */
44
+ declare function createJobPostingJsonLd({ job, board, shareUrl, }: {
45
+ job: PublicJob;
46
+ board: JsonLdBoard;
47
+ shareUrl: string;
48
+ }): JsonLdObject | null;
49
+ /**
50
+ * Prefix `https://` onto scheme-less company websites; `null` for
51
+ * blank input (hosted shape — a whitespace-only website never becomes
52
+ * a bare `https://` `sameAs`).
53
+ */
54
+ declare function normalizeWebsiteUrl(website: string): string | null;
55
+
56
+ /**
57
+ * Compact USD amount in the board language (`$90K`, de: `90.000 $`) — the
58
+ * hosted salary-page money formatter. USD-hardcoded (hosted quirk); the
59
+ * locale drives digits, grouping, and symbol placement only.
60
+ */
61
+ declare function formatUsd(locale: string, value: number): string;
62
+ /** `formatUsd(min) – formatUsd(max)` with the hosted spaced en dash. */
63
+ declare function formatRange(locale: string, min: number, max: number): string;
64
+ /**
65
+ * Seniority display label. Precedence (hosted shape): owner override >
66
+ * board-language lexicon (en = the English source labels) > title-case
67
+ * fallback for an unknown key.
68
+ */
69
+ declare function formatSeniority(locale: string, value: string, overrides?: Record<string, string>): string;
70
+ /** The canonical seniority ladder order the hosted salary pages sort by. */
71
+ declare const SENIORITY_ORDER: readonly ["entry_level", "associate", "mid_level", "senior", "lead", "principal", "director", "executive"];
72
+ /** Sort rows by `SENIORITY_ORDER` (unknown keys sink to the end). Non-mutating. */
73
+ declare function sortBySeniority<T extends {
74
+ seniority: string;
75
+ }>(items: T[]): T[];
76
+ interface FaqItem {
77
+ q: string;
78
+ a: string;
79
+ }
80
+ /**
81
+ * A templated salary FAQ (interim — see the module doc). The sentences are
82
+ * English; the embedded range is board-language-formatted via `formatRange`
83
+ * (the only part hosted localizes). Empty when there is no overall figure.
84
+ */
85
+ declare function buildSalaryFaq(locale: string, label: string, overall: {
86
+ avgMin: number;
87
+ avgMax: number;
88
+ jobCount: number;
89
+ } | null): FaqItem[];
90
+ /** An `ItemList` for a salary index page (the listing's items + their URLs). */
91
+ declare function itemListJsonLd(items: {
92
+ name: string;
93
+ url: string;
94
+ }[]): JsonLdObject | null;
95
+ /** A `FAQPage` from `buildSalaryFaq` items (or any `{q,a}` list). */
96
+ declare function faqJsonLd(faqs: FaqItem[]): JsonLdObject | null;
97
+ /**
98
+ * `Occupation` for a job-title salary page. Per-seniority distribution
99
+ * names embed the board-language seniority label (`formatSeniority`).
100
+ */
101
+ declare function titleSalaryJsonLd(locale: string, d: TitleSalaryDetail): JsonLdObject | null;
102
+ /** `Occupation` for a skill salary page (overall distribution + median). */
103
+ declare function skillSalaryJsonLd(d: SkillSalaryDetail): JsonLdObject | null;
104
+ /**
105
+ * `Occupation` for a location salary page. City-level pages only (the
106
+ * hosted page gates on city/locality); `null` otherwise.
107
+ */
108
+ declare function locationSalaryJsonLd(d: LocationSalaryDetail): JsonLdObject | null;
109
+ /**
110
+ * Cross-axis (title×location / skill×location) `Occupation` JSON-LD. Takes
111
+ * primitives to stay decoupled from the two cross-axis detail wire types.
112
+ */
113
+ declare function crossAxisSalaryJsonLd(locale: string, args: {
114
+ name: string;
115
+ placeName: string;
116
+ countryCode: string;
117
+ overall: {
118
+ avgMin: number;
119
+ avgMax: number;
120
+ p25Min: number | null;
121
+ p75Max: number | null;
122
+ } | null;
123
+ bySeniority: {
124
+ seniority: string;
125
+ avgSalaryMin: number;
126
+ avgSalaryMax: number;
127
+ }[];
128
+ currency: string;
129
+ }): JsonLdObject | null;
130
+ /**
131
+ * `OccupationAggregationByEmployer` for a company's salary overview —
132
+ * mirrors the hosted company-salary page's Google-salary structured data
133
+ * (base + per-seniority distributions, the board median/IQR baseline as
134
+ * the aggregate stats).
135
+ */
136
+ declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdObject | null;
137
+ /** `Occupation` for one job category at a company (the hosted category page). */
138
+ declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
139
+
140
+ interface BreadcrumbItemInput {
141
+ label: string | null | undefined;
142
+ href?: string | null;
143
+ }
144
+ /**
145
+ * Build a `BreadcrumbList`, hosted semantics: labels are trimmed and empty
146
+ * items dropped; fewer than 2 surviving items → `null` (a single crumb is
147
+ * not a trail); the current page (no `href`) omits `item` per schema.org.
148
+ * Relative hrefs resolve against `options.origin`; without an origin a
149
+ * relative item is omitted (never emit a relative `item` URL).
150
+ */
151
+ declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
152
+ origin?: string | null;
153
+ }): JsonLdObject | null;
154
+ /**
155
+ * Home › Jobs › [country › region › city] › primaryCategory › Title.
156
+ * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
157
+ * the category crumb nests under the most-specific place when present
158
+ * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
159
+ * crumb (the job title) carries no `path` — the current page. Mirrors
160
+ * page.tsx:336-367.
161
+ *
162
+ * The Home/Jobs crumb names resolve from the copy catalog per board
163
+ * language ⊕ operator overrides; omitting `language` keeps the
164
+ * English source, so existing call sites render unchanged.
165
+ */
166
+ declare function buildJobBreadcrumbs(job: PublicJob, language?: string, labels?: BoardLabelOverrides): Array<{
167
+ name: string;
168
+ path?: string;
169
+ }>;
170
+
171
+ export { ALL_COUNTRY_CODES as A, type BreadcrumbItemInput as B, type FaqItem as F, type JsonLdObject as J, SENIORITY_ORDER as S, formatUsd as a, buildJobBreadcrumbs as b, type JsonLdBoard as c, buildSalaryFaq as d, companyCategorySalaryJsonLd as e, formatRange as f, companySalaryJsonLd as g, createBreadcrumbJsonLd as h, createJobPostingJsonLd as i, crossAxisSalaryJsonLd as j, faqJsonLd as k, formatSeniority as l, itemListJsonLd as m, normalizeWebsiteUrl as n, locationSalaryJsonLd as o, sortBySeniority as p, skillSalaryJsonLd as s, titleSalaryJsonLd as t };