@cavuno/board 3.1.0 → 4.0.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 (77) hide show
  1. package/CHANGELOG.md +421 -0
  2. package/README.md +6 -2
  3. package/dist/{_spec-nkWAraS0.d.mts → _spec-GVe6WAfT.d.mts} +68 -59
  4. package/dist/{_spec-nkWAraS0.d.ts → _spec-GVe6WAfT.d.ts} +68 -59
  5. package/dist/bin.mjs +7 -2
  6. package/dist/blog-BsmKizpd.d.ts +29 -0
  7. package/dist/blog-Cf64mI8A.d.mts +29 -0
  8. package/dist/{salaries-BahBpxWT.d.ts → board-DUhgiacm.d.ts} +17 -29
  9. package/dist/{salaries-ChSqDBAM.d.mts → board-GGWJ4coe.d.mts} +17 -29
  10. package/dist/breadcrumbs-DFKr0HzU.d.mts +372 -0
  11. package/dist/breadcrumbs-DiccJhk4.d.ts +372 -0
  12. package/dist/chunk-2ETP5UH4.mjs +271 -0
  13. package/dist/chunk-BGKNXG4H.mjs +146 -0
  14. package/dist/chunk-DLSO6XXY.mjs +33 -0
  15. package/dist/chunk-T2KC6XGV.mjs +1060 -0
  16. package/dist/chunk-YEAQ3JEI.mjs +853 -0
  17. package/dist/doctor.js +1 -1
  18. package/dist/doctor.mjs +1 -1
  19. package/dist/filters.d.mts +25 -20
  20. package/dist/filters.d.ts +25 -20
  21. package/dist/filters.js +3 -692
  22. package/dist/filters.mjs +3 -690
  23. package/dist/format.d.mts +57 -230
  24. package/dist/format.d.ts +57 -230
  25. package/dist/format.js +355 -927
  26. package/dist/format.mjs +213 -931
  27. package/dist/go.js +11 -1
  28. package/dist/go.mjs +4 -29
  29. package/dist/index.d.mts +23 -75
  30. package/dist/index.d.ts +23 -75
  31. package/dist/index.js +11 -36
  32. package/dist/index.mjs +32 -313
  33. package/dist/{jobs-lVvKCBCU.d.mts → jobs-BuLpV8iy.d.mts} +4 -4
  34. package/dist/{jobs-BiEvL9d7.d.ts → jobs-QrbXOYB9.d.ts} +4 -4
  35. package/dist/paths.d.mts +89 -1
  36. package/dist/paths.d.ts +89 -1
  37. package/dist/paths.js +62 -14
  38. package/dist/paths.mjs +29 -78
  39. package/dist/route-contract.js +23 -13
  40. package/dist/route-contract.mjs +30 -1079
  41. package/dist/{search-CCyFWPi3.d.mts → search-Cr4noJJZ.d.mts} +14 -3
  42. package/dist/{search-CyRvVMUp.d.ts → search-DdsniXQv.d.ts} +14 -3
  43. package/dist/seo.d.mts +33 -189
  44. package/dist/seo.d.ts +33 -189
  45. package/dist/seo.js +197 -718
  46. package/dist/seo.mjs +44 -1417
  47. package/dist/server.d.mts +5 -5
  48. package/dist/server.d.ts +5 -5
  49. package/dist/server.mjs +5 -31
  50. package/dist/sitemap.d.mts +5 -5
  51. package/dist/sitemap.d.ts +5 -5
  52. package/dist/sitemap.js +25 -14
  53. package/dist/sitemap.mjs +22 -97
  54. package/dist/skills.js +1 -1
  55. package/dist/skills.mjs +1 -1
  56. package/dist/suggest.d.mts +2 -2
  57. package/dist/suggest.d.ts +2 -2
  58. package/dist/suggest.js +17 -3
  59. package/dist/suggest.mjs +17 -3
  60. package/dist/well-known.js +23 -13
  61. package/dist/well-known.mjs +4 -421
  62. package/package.json +5 -4
  63. package/skills/cavuno-board-applications/SKILL.md +4 -1
  64. package/skills/cavuno-board-filters/SKILL.md +11 -12
  65. package/skills/cavuno-board-format/SKILL.md +68 -56
  66. package/skills/cavuno-board-i18n/SKILL.md +102 -21
  67. package/skills/cavuno-board-search-suggestions/SKILL.md +8 -3
  68. package/skills/cavuno-board-seo/BLOG.md +4 -1
  69. package/skills/cavuno-board-seo/JOB_AND_BREADCRUMBS.md +5 -2
  70. package/skills/cavuno-board-seo/LISTING.md +35 -12
  71. package/skills/cavuno-board-seo/SALARY.md +83 -18
  72. package/skills/cavuno-board-seo/SKILL.md +3 -2
  73. package/skills/manifest.json +3 -3
  74. package/dist/board-NE98PlwN.d.ts +0 -16
  75. package/dist/board-muu8BI8P.d.mts +0 -16
  76. package/dist/ui-copy-CCkz6CVF.d.mts +0 -230
  77. package/dist/ui-copy-CCkz6CVF.d.ts +0 -230
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-nkWAraS0.mjs';
1
+ import { S as Schemas } from './_spec-GVe6WAfT.mjs';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -69,13 +69,24 @@ declare class BoardClient {
69
69
  type SuggestResult = Schemas['SuggestResult'];
70
70
  type SuggestionItem = Schemas['SuggestionItem'];
71
71
  type CompanySuggestion = Schemas['CompanySuggestion'];
72
+ type MarketSuggestion = Schemas['MarketSuggestion'];
72
73
  type TermSuggestion = Schemas['TermSuggestion'];
74
+ /** Kinds accepted by `SearchSuggestQuery.types`. */
75
+ type SearchSuggestType = 'company' | 'category' | 'skill' | 'market' | 'post' | 'tag';
73
76
  /** Query for `board.search.suggest()`. */
74
77
  type SearchSuggestQuery = {
75
78
  /** Keyword; under 2 chars the server returns an empty `items` array. */
76
79
  q?: string;
77
- /** Max interleaved suggestions (1–25; default 25). */
80
+ /**
81
+ * Max interleaved suggestions after type filtering (1–25; default 25).
82
+ * With `types: ['skill']`, this is "up to N skills", not N of a mixed pool.
83
+ */
78
84
  limit?: number;
85
+ /**
86
+ * Include only these suggestion kinds. Omit for every kind (company,
87
+ * category, skill, market, post, tag). Repeated query keys on the wire.
88
+ */
89
+ types?: SearchSuggestType[];
79
90
  };
80
91
 
81
- export { type Awaitable as A, type BoardRequest as B, type CompanySuggestion as C, type FetchOptions as F, type Logger as L, REFRESH_TOKEN_KEY as R, type StorageMode as S, type TermSuggestion as T, BoardClient as a, type SearchSuggestQuery as b, ACCESS_TOKEN_KEY as c, BOARD_ACCESS_GRANT_KEY as d, type CustomStorage as e, type SuggestResult as f, type SuggestionItem as g };
92
+ export { type Awaitable as A, type BoardRequest as B, type CompanySuggestion as C, type FetchOptions as F, type Logger as L, type MarketSuggestion as M, REFRESH_TOKEN_KEY as R, type StorageMode as S, type TermSuggestion as T, BoardClient as a, type SearchSuggestQuery as b, ACCESS_TOKEN_KEY as c, BOARD_ACCESS_GRANT_KEY as d, type CustomStorage as e, type SearchSuggestType as f, type SuggestResult as g, type SuggestionItem as h };
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-nkWAraS0.js';
1
+ import { S as Schemas } from './_spec-GVe6WAfT.js';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -69,13 +69,24 @@ declare class BoardClient {
69
69
  type SuggestResult = Schemas['SuggestResult'];
70
70
  type SuggestionItem = Schemas['SuggestionItem'];
71
71
  type CompanySuggestion = Schemas['CompanySuggestion'];
72
+ type MarketSuggestion = Schemas['MarketSuggestion'];
72
73
  type TermSuggestion = Schemas['TermSuggestion'];
74
+ /** Kinds accepted by `SearchSuggestQuery.types`. */
75
+ type SearchSuggestType = 'company' | 'category' | 'skill' | 'market' | 'post' | 'tag';
73
76
  /** Query for `board.search.suggest()`. */
74
77
  type SearchSuggestQuery = {
75
78
  /** Keyword; under 2 chars the server returns an empty `items` array. */
76
79
  q?: string;
77
- /** Max interleaved suggestions (1–25; default 25). */
80
+ /**
81
+ * Max interleaved suggestions after type filtering (1–25; default 25).
82
+ * With `types: ['skill']`, this is "up to N skills", not N of a mixed pool.
83
+ */
78
84
  limit?: number;
85
+ /**
86
+ * Include only these suggestion kinds. Omit for every kind (company,
87
+ * category, skill, market, post, tag). Repeated query keys on the wire.
88
+ */
89
+ types?: SearchSuggestType[];
79
90
  };
80
91
 
81
- export { type Awaitable as A, type BoardRequest as B, type CompanySuggestion as C, type FetchOptions as F, type Logger as L, REFRESH_TOKEN_KEY as R, type StorageMode as S, type TermSuggestion as T, BoardClient as a, type SearchSuggestQuery as b, ACCESS_TOKEN_KEY as c, BOARD_ACCESS_GRANT_KEY as d, type CustomStorage as e, type SuggestResult as f, type SuggestionItem as g };
92
+ export { type Awaitable as A, type BoardRequest as B, type CompanySuggestion as C, type FetchOptions as F, type Logger as L, type MarketSuggestion as M, REFRESH_TOKEN_KEY as R, type StorageMode as S, type TermSuggestion as T, BoardClient as a, type SearchSuggestQuery as b, ACCESS_TOKEN_KEY as c, BOARD_ACCESS_GRANT_KEY as d, type CustomStorage as e, type SearchSuggestType as f, type SuggestResult as g, type SuggestionItem as h };
package/dist/seo.d.mts CHANGED
@@ -1,59 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, a as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-ChSqDBAM.mjs';
2
- import { P as PublicBoard } from './board-muu8BI8P.mjs';
3
- import { P as PublicJob } from './jobs-lVvKCBCU.mjs';
4
- import { B as BoardLabelOverrides } from './ui-copy-CCkz6CVF.mjs';
5
- import './_spec-nkWAraS0.mjs';
6
-
7
- /**
8
- * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
9
- * types, transcribed field-by-field from the hosted board's generator
10
- * (the hosted board implementation + `job-posting-location-json-ld.ts`) and
11
- * tested against the hosted behavior.
12
- *
13
- * JSON-LD structure is locale-neutral per schema.org — no board-language
14
- * parameter here; the only display strings are wire values passed through.
15
- *
16
- * Named exclusions (hosted behaviours with no wire twin, recorded in the
17
- * public API contract):
18
- * - `board.companyLegalName` — hosted falls back to it for the
19
- * organization name between `company.name` and `board.name`; the wire
20
- * board context does not expose it.
21
- * - `board.companyWebsiteUrl` — hosted falls back to it for `sameAs` when
22
- * the company has no website; not on the wire.
23
- * - the hosted `job.place`/`locationLabel` jobLocation fallback (used when
24
- * a job has no office locations) — the wire `PublicJob` carries no
25
- * resolved place geo, only `officeLocations`.
26
- */
27
-
28
- type JsonLdObject = Record<string, unknown>;
29
- /** The only board fields JSON-LD needs — keeps callers' shapes flexible. */
30
- type JsonLdBoard = Pick<PublicBoard, 'name' | 'logoUrl'>;
31
- /**
32
- * Worldwide-remote jobs must still emit `applicantLocationRequirements`
33
- * next to TELECOMMUTE (Google requires a location signal), so the hosted
34
- * board — and this transcription — lists every country it recognises.
35
- *
36
- * This is the hosted board's exact country catalog: sorted by English common
37
- * name, includes `XK` (Kosovo), and excludes `KP` (North Korea). tested
38
- * against the hosted list so the two cannot drift.
39
- */
40
- 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"];
41
- /**
42
- * Build the Google for Jobs `JobPosting` JSON-LD object for a job detail
43
- * page, or `null` when nothing renderable remains after pruning. Embed the
44
- * result in a `<script type="application/ld+json">` tag.
45
- */
46
- declare function createJobPostingJsonLd({ job, board, shareUrl, }: {
47
- job: PublicJob;
48
- board: JsonLdBoard;
49
- shareUrl: string;
50
- }): JsonLdObject | null;
51
- /**
52
- * Prefix `https://` onto scheme-less company websites; `null` for
53
- * blank input (hosted shape — a whitespace-only website never becomes
54
- * a bare `https://` `sameAs`).
55
- */
56
- declare function normalizeWebsiteUrl(website: string): string | null;
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-Cf64mI8A.mjs';
2
+ import { e as JsonLdObject } from './breadcrumbs-DFKr0HzU.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-DFKr0HzU.mjs';
4
+ import './_spec-GVe6WAfT.mjs';
5
+ import './board-GGWJ4coe.mjs';
6
+ import './jobs-BuLpV8iy.mjs';
57
7
 
58
8
  /**
59
9
  * Blog structured data on the `@cavuno/board` wire types, transcribed from
@@ -108,60 +58,32 @@ declare function createAuthorProfileJsonLd({ author, canonical, description, ori
108
58
  totalPosts: number;
109
59
  }): JsonLdObject | null;
110
60
 
111
- interface BreadcrumbItemInput {
112
- label: string | null | undefined;
113
- href?: string | null;
114
- }
115
- /**
116
- * Build a `BreadcrumbList`, hosted semantics: labels are trimmed and empty
117
- * items dropped; fewer than 2 surviving items → `null` (a single crumb is
118
- * not a trail); the current page (no `href`) omits `item` per schema.org.
119
- * Relative hrefs resolve against `options.origin`; without an origin a
120
- * relative item is omitted (never emit a relative `item` URL).
121
- */
122
- declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
123
- origin?: string | null;
124
- }): JsonLdObject | null;
125
- /**
126
- * Home › Jobs › [country › region › city] › primaryCategory › Title.
127
- * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
128
- * the category crumb nests under the most-specific place when present
129
- * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
130
- * crumb (the job title) carries no `path` — the current page. Mirrors
131
- * page.tsx:336-367.
132
- *
133
- * The Home/Jobs crumb names resolve from the copy catalog per board
134
- * language ⊕ operator overrides; omitting `language` keeps the
135
- * English source, so existing call sites render unchanged.
136
- */
137
- declare function buildJobBreadcrumbs(job: PublicJob, language?: string, labels?: BoardLabelOverrides): Array<{
138
- name: string;
139
- path?: string;
140
- }>;
141
-
142
- /**
143
- * Framework-neutral `<head>` + structural JSON-LD builders for jobs-listing
144
- * pages. Locale-neutral pass-through: the caller supplies the
145
- * heading/board copy (title/description COPY is board-SEO-config +
146
- * localized — a named exclusion; these builders replicate the hosted
147
- * STRUCTURE: title with result count, canonical, Open Graph, breadcrumb +
148
- * job `ItemList`).
149
- */
150
-
151
61
  interface ListingHeadOptions {
152
- boardName: string;
62
+ /**
63
+ * Fully composed document title — application owns counters, particles,
64
+ * word order, and separators (e.g. `1,225 Jobs | Acme`, `1.225 Jobs | Acme`,
65
+ * `1,225件の求人 | 求人ボード`). The SDK does not join count/heading/board.
66
+ */
67
+ title: string;
153
68
  origin: string;
154
69
  /** Absolute path of THIS page, for canonical / og:url, e.g. `/jobs/robotik`. */
155
70
  path: string;
156
- /** Human heading, e.g. `Robotik jobs in Berlin` or `Jobs`. */
157
- heading: string;
158
- /** Result count — prefixed into the title (`N heading`). */
159
- count?: number;
71
+ /**
72
+ * Meta description — fully owned by the application. Pass a sentence from
73
+ * the board's copy source (page config, message catalog, template). The SDK
74
+ * does not invent or case-fold this string.
75
+ */
76
+ description: string;
160
77
  }
161
78
  /**
162
- * Meta/link descriptors for a jobs-listing page — title (with result
163
- * count), meta description, Open Graph, and `<link rel=canonical>`.
164
- * Framework-neutral: map `meta`/`links` into your head manager.
79
+ * Meta/link descriptors for a jobs-listing page — caller-supplied title and
80
+ * meta description, Open Graph, and `<link rel=canonical>`. Framework-neutral:
81
+ * map `meta`/`links` into your head manager.
82
+ *
83
+ * **Why `title` and `description` are both accepted composed:** a function
84
+ * that takes a finished description but still composes its own title from
85
+ * count/heading/boardName is incoherent — both are display sentences whose
86
+ * arrangement is locale-dependent (Japanese counters, RTL order, …).
165
87
  */
166
88
  declare function listingHead(options: ListingHeadOptions): {
167
89
  meta: ({
@@ -196,6 +118,12 @@ interface JobLink {
196
118
  * page, mirroring the structural JSON-LD the hosted board emits. The rich
197
119
  * category set (`Occupation`/`FAQPage`/`MonetaryAmountDistribution`) lives
198
120
  * in `./salary` — feed it the salary detail reads.
121
+ *
122
+ * Empty / single-crumb trails omit `BreadcrumbList` (same min-2 rule as
123
+ * `createBreadcrumbJsonLd` — an empty `itemListElement` is invalid structured
124
+ * data). Job URLs go through `jobDetailPath` — `/jobs/{slug}` is always a
125
+ * listing route, never a job detail; company-less jobs are dropped from the
126
+ * ItemList rather than linked to an invalid path.
199
127
  */
200
128
  declare function listingJsonLd(options: {
201
129
  origin: string;
@@ -207,88 +135,4 @@ declare function listingJsonLd(options: {
207
135
  jobs?: JobLink[];
208
136
  }): JsonLdObject[];
209
137
 
210
- /**
211
- * Compact USD amount in the board language (`$90K`, de: `90.000 $`) — the
212
- * hosted salary-page money formatter. USD-hardcoded (hosted quirk); the
213
- * locale drives digits, grouping, and symbol placement only.
214
- */
215
- declare function formatUsd(locale: string, value: number): string;
216
- /** `formatUsd(min) – formatUsd(max)` with the hosted spaced en dash. */
217
- declare function formatRange(locale: string, min: number, max: number): string;
218
- /**
219
- * Seniority display label. Precedence (hosted shape): owner override >
220
- * board-language lexicon (en = the English source labels) > title-case
221
- * fallback for an unknown key.
222
- */
223
- declare function formatSeniority(locale: string, value: string, overrides?: Record<string, string>): string;
224
- /** The canonical seniority ladder order the hosted salary pages sort by. */
225
- declare const SENIORITY_ORDER: readonly ["entry_level", "associate", "mid_level", "senior", "lead", "principal", "director", "executive"];
226
- /** Sort rows by `SENIORITY_ORDER` (unknown keys sink to the end). Non-mutating. */
227
- declare function sortBySeniority<T extends {
228
- seniority: string;
229
- }>(items: T[]): T[];
230
- interface FaqItem {
231
- q: string;
232
- a: string;
233
- }
234
- /**
235
- * A templated salary FAQ (interim — see the module doc). The sentences are
236
- * English; the embedded range is board-language-formatted via `formatRange`
237
- * (the only part hosted localizes). Empty when there is no overall figure.
238
- */
239
- declare function buildSalaryFaq(locale: string, label: string, overall: {
240
- avgMin: number;
241
- avgMax: number;
242
- jobCount: number;
243
- } | null): FaqItem[];
244
- /** An `ItemList` for a salary index page (the listing's items + their URLs). */
245
- declare function itemListJsonLd(items: {
246
- name: string;
247
- url: string;
248
- }[]): JsonLdObject | null;
249
- /** A `FAQPage` from `buildSalaryFaq` items (or any `{q,a}` list). */
250
- declare function faqJsonLd(faqs: FaqItem[]): JsonLdObject | null;
251
- /**
252
- * `Occupation` for a job-title salary page. Per-seniority distribution
253
- * names embed the board-language seniority label (`formatSeniority`).
254
- */
255
- declare function titleSalaryJsonLd(locale: string, d: TitleSalaryDetail): JsonLdObject | null;
256
- /** `Occupation` for a skill salary page (overall distribution + median). */
257
- declare function skillSalaryJsonLd(d: SkillSalaryDetail): JsonLdObject | null;
258
- /**
259
- * `Occupation` for a location salary page. City-level pages only (the
260
- * hosted page gates on city/locality); `null` otherwise.
261
- */
262
- declare function locationSalaryJsonLd(d: LocationSalaryDetail): JsonLdObject | null;
263
- /**
264
- * Cross-axis (title×location / skill×location) `Occupation` JSON-LD. Takes
265
- * primitives to stay decoupled from the two cross-axis detail wire types.
266
- */
267
- declare function crossAxisSalaryJsonLd(locale: string, args: {
268
- name: string;
269
- placeName: string;
270
- countryCode: string;
271
- overall: {
272
- avgMin: number;
273
- avgMax: number;
274
- p25Min: number | null;
275
- p75Max: number | null;
276
- } | null;
277
- bySeniority: {
278
- seniority: string;
279
- avgSalaryMin: number;
280
- avgSalaryMax: number;
281
- }[];
282
- currency: string;
283
- }): JsonLdObject | null;
284
- /**
285
- * `OccupationAggregationByEmployer` for a company's salary overview —
286
- * mirrors the hosted company-salary page's Google-salary structured data
287
- * (base + per-seniority distributions, the board median/IQR baseline as
288
- * the aggregate stats).
289
- */
290
- declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdObject | null;
291
- /** `Occupation` for one job category at a company (the hosted category page). */
292
- declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
293
-
294
- export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildJobBreadcrumbs, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
138
+ export { type ArticleJsonLdPost, JsonLdObject, type ListingHeadOptions, createAuthorProfileJsonLd, createBlogArticleJsonLd, listingHead, listingJsonLd };
package/dist/seo.d.ts CHANGED
@@ -1,59 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, a as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-BahBpxWT.js';
2
- import { P as PublicBoard } from './board-NE98PlwN.js';
3
- import { P as PublicJob } from './jobs-BiEvL9d7.js';
4
- import { B as BoardLabelOverrides } from './ui-copy-CCkz6CVF.js';
5
- import './_spec-nkWAraS0.js';
6
-
7
- /**
8
- * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
9
- * types, transcribed field-by-field from the hosted board's generator
10
- * (the hosted board implementation + `job-posting-location-json-ld.ts`) and
11
- * tested against the hosted behavior.
12
- *
13
- * JSON-LD structure is locale-neutral per schema.org — no board-language
14
- * parameter here; the only display strings are wire values passed through.
15
- *
16
- * Named exclusions (hosted behaviours with no wire twin, recorded in the
17
- * public API contract):
18
- * - `board.companyLegalName` — hosted falls back to it for the
19
- * organization name between `company.name` and `board.name`; the wire
20
- * board context does not expose it.
21
- * - `board.companyWebsiteUrl` — hosted falls back to it for `sameAs` when
22
- * the company has no website; not on the wire.
23
- * - the hosted `job.place`/`locationLabel` jobLocation fallback (used when
24
- * a job has no office locations) — the wire `PublicJob` carries no
25
- * resolved place geo, only `officeLocations`.
26
- */
27
-
28
- type JsonLdObject = Record<string, unknown>;
29
- /** The only board fields JSON-LD needs — keeps callers' shapes flexible. */
30
- type JsonLdBoard = Pick<PublicBoard, 'name' | 'logoUrl'>;
31
- /**
32
- * Worldwide-remote jobs must still emit `applicantLocationRequirements`
33
- * next to TELECOMMUTE (Google requires a location signal), so the hosted
34
- * board — and this transcription — lists every country it recognises.
35
- *
36
- * This is the hosted board's exact country catalog: sorted by English common
37
- * name, includes `XK` (Kosovo), and excludes `KP` (North Korea). tested
38
- * against the hosted list so the two cannot drift.
39
- */
40
- 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"];
41
- /**
42
- * Build the Google for Jobs `JobPosting` JSON-LD object for a job detail
43
- * page, or `null` when nothing renderable remains after pruning. Embed the
44
- * result in a `<script type="application/ld+json">` tag.
45
- */
46
- declare function createJobPostingJsonLd({ job, board, shareUrl, }: {
47
- job: PublicJob;
48
- board: JsonLdBoard;
49
- shareUrl: string;
50
- }): JsonLdObject | null;
51
- /**
52
- * Prefix `https://` onto scheme-less company websites; `null` for
53
- * blank input (hosted shape — a whitespace-only website never becomes
54
- * a bare `https://` `sameAs`).
55
- */
56
- declare function normalizeWebsiteUrl(website: string): string | null;
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-BsmKizpd.js';
2
+ import { e as JsonLdObject } from './breadcrumbs-DiccJhk4.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-DiccJhk4.js';
4
+ import './_spec-GVe6WAfT.js';
5
+ import './board-DUhgiacm.js';
6
+ import './jobs-QrbXOYB9.js';
57
7
 
58
8
  /**
59
9
  * Blog structured data on the `@cavuno/board` wire types, transcribed from
@@ -108,60 +58,32 @@ declare function createAuthorProfileJsonLd({ author, canonical, description, ori
108
58
  totalPosts: number;
109
59
  }): JsonLdObject | null;
110
60
 
111
- interface BreadcrumbItemInput {
112
- label: string | null | undefined;
113
- href?: string | null;
114
- }
115
- /**
116
- * Build a `BreadcrumbList`, hosted semantics: labels are trimmed and empty
117
- * items dropped; fewer than 2 surviving items → `null` (a single crumb is
118
- * not a trail); the current page (no `href`) omits `item` per schema.org.
119
- * Relative hrefs resolve against `options.origin`; without an origin a
120
- * relative item is omitted (never emit a relative `item` URL).
121
- */
122
- declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
123
- origin?: string | null;
124
- }): JsonLdObject | null;
125
- /**
126
- * Home › Jobs › [country › region › city] › primaryCategory › Title.
127
- * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
128
- * the category crumb nests under the most-specific place when present
129
- * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
130
- * crumb (the job title) carries no `path` — the current page. Mirrors
131
- * page.tsx:336-367.
132
- *
133
- * The Home/Jobs crumb names resolve from the copy catalog per board
134
- * language ⊕ operator overrides; omitting `language` keeps the
135
- * English source, so existing call sites render unchanged.
136
- */
137
- declare function buildJobBreadcrumbs(job: PublicJob, language?: string, labels?: BoardLabelOverrides): Array<{
138
- name: string;
139
- path?: string;
140
- }>;
141
-
142
- /**
143
- * Framework-neutral `<head>` + structural JSON-LD builders for jobs-listing
144
- * pages. Locale-neutral pass-through: the caller supplies the
145
- * heading/board copy (title/description COPY is board-SEO-config +
146
- * localized — a named exclusion; these builders replicate the hosted
147
- * STRUCTURE: title with result count, canonical, Open Graph, breadcrumb +
148
- * job `ItemList`).
149
- */
150
-
151
61
  interface ListingHeadOptions {
152
- boardName: string;
62
+ /**
63
+ * Fully composed document title — application owns counters, particles,
64
+ * word order, and separators (e.g. `1,225 Jobs | Acme`, `1.225 Jobs | Acme`,
65
+ * `1,225件の求人 | 求人ボード`). The SDK does not join count/heading/board.
66
+ */
67
+ title: string;
153
68
  origin: string;
154
69
  /** Absolute path of THIS page, for canonical / og:url, e.g. `/jobs/robotik`. */
155
70
  path: string;
156
- /** Human heading, e.g. `Robotik jobs in Berlin` or `Jobs`. */
157
- heading: string;
158
- /** Result count — prefixed into the title (`N heading`). */
159
- count?: number;
71
+ /**
72
+ * Meta description — fully owned by the application. Pass a sentence from
73
+ * the board's copy source (page config, message catalog, template). The SDK
74
+ * does not invent or case-fold this string.
75
+ */
76
+ description: string;
160
77
  }
161
78
  /**
162
- * Meta/link descriptors for a jobs-listing page — title (with result
163
- * count), meta description, Open Graph, and `<link rel=canonical>`.
164
- * Framework-neutral: map `meta`/`links` into your head manager.
79
+ * Meta/link descriptors for a jobs-listing page — caller-supplied title and
80
+ * meta description, Open Graph, and `<link rel=canonical>`. Framework-neutral:
81
+ * map `meta`/`links` into your head manager.
82
+ *
83
+ * **Why `title` and `description` are both accepted composed:** a function
84
+ * that takes a finished description but still composes its own title from
85
+ * count/heading/boardName is incoherent — both are display sentences whose
86
+ * arrangement is locale-dependent (Japanese counters, RTL order, …).
165
87
  */
166
88
  declare function listingHead(options: ListingHeadOptions): {
167
89
  meta: ({
@@ -196,6 +118,12 @@ interface JobLink {
196
118
  * page, mirroring the structural JSON-LD the hosted board emits. The rich
197
119
  * category set (`Occupation`/`FAQPage`/`MonetaryAmountDistribution`) lives
198
120
  * in `./salary` — feed it the salary detail reads.
121
+ *
122
+ * Empty / single-crumb trails omit `BreadcrumbList` (same min-2 rule as
123
+ * `createBreadcrumbJsonLd` — an empty `itemListElement` is invalid structured
124
+ * data). Job URLs go through `jobDetailPath` — `/jobs/{slug}` is always a
125
+ * listing route, never a job detail; company-less jobs are dropped from the
126
+ * ItemList rather than linked to an invalid path.
199
127
  */
200
128
  declare function listingJsonLd(options: {
201
129
  origin: string;
@@ -207,88 +135,4 @@ declare function listingJsonLd(options: {
207
135
  jobs?: JobLink[];
208
136
  }): JsonLdObject[];
209
137
 
210
- /**
211
- * Compact USD amount in the board language (`$90K`, de: `90.000 $`) — the
212
- * hosted salary-page money formatter. USD-hardcoded (hosted quirk); the
213
- * locale drives digits, grouping, and symbol placement only.
214
- */
215
- declare function formatUsd(locale: string, value: number): string;
216
- /** `formatUsd(min) – formatUsd(max)` with the hosted spaced en dash. */
217
- declare function formatRange(locale: string, min: number, max: number): string;
218
- /**
219
- * Seniority display label. Precedence (hosted shape): owner override >
220
- * board-language lexicon (en = the English source labels) > title-case
221
- * fallback for an unknown key.
222
- */
223
- declare function formatSeniority(locale: string, value: string, overrides?: Record<string, string>): string;
224
- /** The canonical seniority ladder order the hosted salary pages sort by. */
225
- declare const SENIORITY_ORDER: readonly ["entry_level", "associate", "mid_level", "senior", "lead", "principal", "director", "executive"];
226
- /** Sort rows by `SENIORITY_ORDER` (unknown keys sink to the end). Non-mutating. */
227
- declare function sortBySeniority<T extends {
228
- seniority: string;
229
- }>(items: T[]): T[];
230
- interface FaqItem {
231
- q: string;
232
- a: string;
233
- }
234
- /**
235
- * A templated salary FAQ (interim — see the module doc). The sentences are
236
- * English; the embedded range is board-language-formatted via `formatRange`
237
- * (the only part hosted localizes). Empty when there is no overall figure.
238
- */
239
- declare function buildSalaryFaq(locale: string, label: string, overall: {
240
- avgMin: number;
241
- avgMax: number;
242
- jobCount: number;
243
- } | null): FaqItem[];
244
- /** An `ItemList` for a salary index page (the listing's items + their URLs). */
245
- declare function itemListJsonLd(items: {
246
- name: string;
247
- url: string;
248
- }[]): JsonLdObject | null;
249
- /** A `FAQPage` from `buildSalaryFaq` items (or any `{q,a}` list). */
250
- declare function faqJsonLd(faqs: FaqItem[]): JsonLdObject | null;
251
- /**
252
- * `Occupation` for a job-title salary page. Per-seniority distribution
253
- * names embed the board-language seniority label (`formatSeniority`).
254
- */
255
- declare function titleSalaryJsonLd(locale: string, d: TitleSalaryDetail): JsonLdObject | null;
256
- /** `Occupation` for a skill salary page (overall distribution + median). */
257
- declare function skillSalaryJsonLd(d: SkillSalaryDetail): JsonLdObject | null;
258
- /**
259
- * `Occupation` for a location salary page. City-level pages only (the
260
- * hosted page gates on city/locality); `null` otherwise.
261
- */
262
- declare function locationSalaryJsonLd(d: LocationSalaryDetail): JsonLdObject | null;
263
- /**
264
- * Cross-axis (title×location / skill×location) `Occupation` JSON-LD. Takes
265
- * primitives to stay decoupled from the two cross-axis detail wire types.
266
- */
267
- declare function crossAxisSalaryJsonLd(locale: string, args: {
268
- name: string;
269
- placeName: string;
270
- countryCode: string;
271
- overall: {
272
- avgMin: number;
273
- avgMax: number;
274
- p25Min: number | null;
275
- p75Max: number | null;
276
- } | null;
277
- bySeniority: {
278
- seniority: string;
279
- avgSalaryMin: number;
280
- avgSalaryMax: number;
281
- }[];
282
- currency: string;
283
- }): JsonLdObject | null;
284
- /**
285
- * `OccupationAggregationByEmployer` for a company's salary overview —
286
- * mirrors the hosted company-salary page's Google-salary structured data
287
- * (base + per-seniority distributions, the board median/IQR baseline as
288
- * the aggregate stats).
289
- */
290
- declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdObject | null;
291
- /** `Occupation` for one job category at a company (the hosted category page). */
292
- declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
293
-
294
- export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildJobBreadcrumbs, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
138
+ export { type ArticleJsonLdPost, JsonLdObject, type ListingHeadOptions, createAuthorProfileJsonLd, createBlogArticleJsonLd, listingHead, listingJsonLd };