@cavuno/board 1.44.0 → 2.0.1

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 (84) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/CONTRIBUTING.md +25 -0
  3. package/LICENSE +21 -0
  4. package/README.md +12 -7
  5. package/SECURITY.md +28 -0
  6. package/TRADEMARKS.md +16 -0
  7. package/dist/_spec-sW85fuvT.d.mts +2731 -0
  8. package/dist/_spec-sW85fuvT.d.ts +2731 -0
  9. package/dist/bin.mjs +38 -349
  10. package/dist/{board-DZCw7A6P.d.ts → board-DKXyxwNN.d.ts} +2 -2
  11. package/dist/{board-BwFW1aU2.d.mts → board-QFeHT4UN.d.mts} +2 -2
  12. package/dist/doctor.d.mts +6 -19
  13. package/dist/doctor.d.ts +6 -19
  14. package/dist/doctor.js +38 -345
  15. package/dist/doctor.mjs +37 -344
  16. package/dist/filters.d.mts +5 -5
  17. package/dist/filters.d.ts +5 -5
  18. package/dist/format.d.mts +17 -19
  19. package/dist/format.d.ts +17 -19
  20. package/dist/go.d.mts +2 -2
  21. package/dist/go.d.ts +2 -2
  22. package/dist/go.js +1 -1
  23. package/dist/go.mjs +1 -1
  24. package/dist/index.d.mts +16 -18
  25. package/dist/index.d.ts +16 -18
  26. package/dist/index.js +39 -28
  27. package/dist/index.mjs +39 -28
  28. package/dist/{jobs-BVazo4mA.d.ts → jobs-CuRzTDb1.d.mts} +15 -13
  29. package/dist/{jobs-CSMshXGV.d.mts → jobs-DTnCZGtb.d.ts} +15 -13
  30. package/dist/paths.d.mts +6 -6
  31. package/dist/paths.d.ts +6 -6
  32. package/dist/paths.js +1 -1
  33. package/dist/paths.mjs +1 -1
  34. package/dist/roles-vY0AXhoc.d.mts +3 -3
  35. package/dist/roles-vY0AXhoc.d.ts +3 -3
  36. package/dist/route-contract.d.mts +16 -16
  37. package/dist/route-contract.d.ts +16 -16
  38. package/dist/route-contract.js +1 -1
  39. package/dist/route-contract.mjs +1 -1
  40. package/dist/{salaries-DMQsjLrV.d.ts → salaries-BOpR51Ny.d.mts} +3 -3
  41. package/dist/{salaries-IJlchnWk.d.mts → salaries-QoNpzRCT.d.ts} +3 -3
  42. package/dist/{search-B7gr_wOd.d.ts → search-B5ROY6PK.d.ts} +2 -2
  43. package/dist/{search-B6FJifRE.d.mts → search-f93nrSg3.d.mts} +2 -2
  44. package/dist/seo.d.mts +17 -18
  45. package/dist/seo.d.ts +17 -18
  46. package/dist/server.d.mts +14 -32
  47. package/dist/server.d.ts +14 -32
  48. package/dist/sitemap.d.mts +7 -7
  49. package/dist/sitemap.d.ts +7 -7
  50. package/dist/sitemap.js +4 -2
  51. package/dist/sitemap.mjs +4 -2
  52. package/dist/skills.d.mts +1 -1
  53. package/dist/skills.d.ts +1 -1
  54. package/dist/skills.js +1 -1
  55. package/dist/suggest.d.mts +2 -2
  56. package/dist/suggest.d.ts +2 -2
  57. package/dist/theme.d.mts +10 -13
  58. package/dist/theme.d.ts +10 -13
  59. package/dist/theme.js +1 -1
  60. package/dist/theme.mjs +1 -1
  61. package/dist/{ui-copy-CKfFTtLk.d.mts → ui-copy-CL-VN1xb.d.mts} +2 -3
  62. package/dist/{ui-copy-CKfFTtLk.d.ts → ui-copy-CL-VN1xb.d.ts} +2 -3
  63. package/dist/well-known.d.mts +3 -3
  64. package/dist/well-known.d.ts +3 -3
  65. package/dist/well-known.js +1 -1
  66. package/dist/well-known.mjs +1 -1
  67. package/package.json +46 -38
  68. package/skills/cavuno-board-client/SKILL.md +1 -2
  69. package/skills/cavuno-board-filters/SKILL.md +2 -2
  70. package/skills/cavuno-board-format/SKILL.md +1 -1
  71. package/skills/cavuno-board-i18n/SKILL.md +3 -3
  72. package/skills/cavuno-board-job-posting/SKILL.md +1 -1
  73. package/skills/cavuno-board-messaging/SKILL.md +2 -3
  74. package/skills/cavuno-board-paywall/SKILL.md +1 -1
  75. package/skills/cavuno-board-salaries/SKILL.md +1 -1
  76. package/skills/cavuno-board-seo/SKILL.md +4 -6
  77. package/skills/cavuno-board-server/SKILL.md +1 -1
  78. package/skills/cavuno-board-setup/SKILL.md +2 -1
  79. package/skills/cavuno-board-sitemap/SKILL.md +1 -1
  80. package/skills/cavuno-board-smoke-test/SKILL.md +4 -13
  81. package/skills/flavors/tanstack-start/SKILL.md +1 -2
  82. package/skills/manifest.json +1 -1
  83. package/dist/_spec-CoL3oYpG.d.mts +0 -5296
  84. package/dist/_spec-CoL3oYpG.d.ts +0 -5296
package/dist/sitemap.mjs CHANGED
@@ -186,7 +186,7 @@ var BOARD_PATHS = {
186
186
  talent: "/talent",
187
187
  employers: "/employers",
188
188
  /**
189
- * Alert-email surfaces (ADR-0090 D1/D4). Promoted out of raw literals in
189
+ * Alert-email surfaces. Promoted out of raw literals in
190
190
  * the job-alerts composer so /go indirection and email composition share
191
191
  * one definition.
192
192
  */
@@ -303,7 +303,9 @@ async function jobsTaxonomy(board, origin, kind) {
303
303
  async function jobsLocations(board, origin) {
304
304
  const { language } = await board.context();
305
305
  const { data } = await board.salaries.locations.list({ locale: language });
306
- return data.filter((l) => l.jobCount >= MIN_JOBS_PER_INDEXED_PAGE).map((l) => l.placeSlug).sort().map((slug) => `${origin}${jobsLocationPath(slug)}`);
306
+ return data.filter(
307
+ (location) => location.jobCount >= MIN_JOBS_PER_INDEXED_PAGE
308
+ ).map((location) => location.placeSlug).sort().map((slug) => `${origin}${jobsLocationPath(slug)}`);
307
309
  }
308
310
  async function jobDetails(board, origin) {
309
311
  const jobs = await enumerateJobs(board);
package/dist/skills.d.mts CHANGED
@@ -21,7 +21,7 @@ interface SkillManifest {
21
21
  * Skill-corpus loader. Node-only (reads the shipped `skills/` directory from
22
22
  * the installed package) — kept out of the isomorphic core and exposed via the
23
23
  * `@cavuno/board/skills` subpath export. Both `npx @cavuno/board setup` and the
24
- * in-admin sidekick (ADR-0033) read the corpus through here, so the two doors
24
+ * in-admin sidekick read the corpus through here, so the two doors
25
25
  * stay fed from one source.
26
26
  */
27
27
 
package/dist/skills.d.ts CHANGED
@@ -21,7 +21,7 @@ interface SkillManifest {
21
21
  * Skill-corpus loader. Node-only (reads the shipped `skills/` directory from
22
22
  * the installed package) — kept out of the isomorphic core and exposed via the
23
23
  * `@cavuno/board/skills` subpath export. Both `npx @cavuno/board setup` and the
24
- * in-admin sidekick (ADR-0033) read the corpus through here, so the two doors
24
+ * in-admin sidekick read the corpus through here, so the two doors
25
25
  * stay fed from one source.
26
26
  */
27
27
 
package/dist/skills.js CHANGED
@@ -26,7 +26,7 @@ __export(skills_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(skills_exports);
28
28
 
29
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.4/node_modules/tsup/assets/cjs_shims.js
29
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
30
30
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
31
31
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
32
32
 
@@ -1,5 +1,5 @@
1
- import { S as SuggestionItem, a as SearchSuggestQuery, F as FetchOptions, b as SuggestResult } from './search-B6FJifRE.mjs';
2
- import './_spec-CoL3oYpG.mjs';
1
+ import { S as SuggestionItem, a as SearchSuggestQuery, F as FetchOptions, b as SuggestResult } from './search-f93nrSg3.mjs';
2
+ import './_spec-sW85fuvT.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 { S as SuggestionItem, a as SearchSuggestQuery, F as FetchOptions, b as SuggestResult } from './search-B7gr_wOd.js';
2
- import './_spec-CoL3oYpG.js';
1
+ import { S as SuggestionItem, a as SearchSuggestQuery, F as FetchOptions, b as SuggestResult } from './search-B5ROY6PK.js';
2
+ import './_spec-sW85fuvT.js';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/suggest` — framework-agnostic headless search-suggest
package/dist/theme.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `@cavuno/board/theme` — board theme → shadcn CSS-variable overrides
3
- * (ADR-0057).
3
+ *.
4
4
  *
5
5
  * The board's stored theme (16 semantic colors × light/dark from
6
6
  * `board.context().theme`) is mapped onto the canonical shadcn token
@@ -8,7 +8,7 @@
8
8
  * contract, two consumers: the dashboard edits the board theme, and agents
9
9
  * restyle through the standard shadcn theme file — both end up in the same
10
10
  * tokens. The hosted board renders the same 16 source colors through its
11
- * own token system; a coverage golden in-monorepo asserts neither side
11
+ * own token system; a coverage golden asserts neither side
12
12
  * silently drops a color key.
13
13
  *
14
14
  * A null theme emits nothing — the app's static default theme applies
@@ -41,8 +41,8 @@ interface ThemeInput {
41
41
  */
42
42
  declare function isSafeThemeColorValue(value: string): boolean;
43
43
  /**
44
- * Email-safe snapshot keys (platform brand snapshot / MIG-04).
45
- * Light-only subset consumed by Convex email branding.
44
+ * Email-safe snapshot keys.
45
+ * Light-only subset consumed by server-rendered email branding.
46
46
  */
47
47
  type EmailSafeSnapshotColorKey = 'buttonPrimary' | 'buttonPrimaryText' | 'background' | 'mutedBackground' | 'border' | 'text' | 'textMuted' | 'brandColor';
48
48
  /**
@@ -53,7 +53,7 @@ type EmailSafeSnapshotColorKey = 'buttonPrimary' | 'buttonPrimaryText' | 'backgr
53
53
  * mutedBackground). Within one CSS property name, multi-`:root` cascade
54
54
  * is last-wins and is resolved before this table is consulted.
55
55
  *
56
- * Additive export for the platform brand-snapshot deriver (MIG-04) —
56
+ * Additive export for the platform brand-snapshot deriver —
57
57
  * keeps the CSS ↔ board contract next to its forward twin.
58
58
  */
59
59
  declare const EMAIL_SAFE_SNAPSHOT_FROM_CSS: {
@@ -62,7 +62,7 @@ declare const EMAIL_SAFE_SNAPSHOT_FROM_CSS: {
62
62
  /**
63
63
  * Board key → CSS custom property name(s) (no `--` prefix).
64
64
  *
65
- * The forward write contract for the builder theme tab (MIG-05) and the
65
+ * The forward write contract for the builder theme tab and the
66
66
  * emission table for `boardThemeToCss` / `tokenLines` — one table, so a
67
67
  * tab edit and a render path cannot drift. When a board key fans out to
68
68
  * several CSS names (e.g. `text` → foreground + card-foreground + …),
@@ -77,12 +77,9 @@ declare const BOARD_COLOR_TO_CSS_TOKENS: {
77
77
  readonly [K in BoardColorKey]: readonly string[];
78
78
  };
79
79
  /**
80
- * CSS custom property names (no `--`) that fan out from *optional*
81
- * ColorTokensSchema keys (`textSubtle`, `textDisabled`). Production
82
- * starter `tokens.css` may omit these declarations; the builder theme
83
- * batch lane SKIPS missing optional declarations rather than escalating
84
- * the whole preset to the model (MIG-05). Required declarations still
85
- * escalate on absence — never invent (L5-B).
80
+ * CSS custom property names (without `--`) backed by optional color tokens.
81
+ * A starter may omit these declarations; required declarations must still
82
+ * be present.
86
83
  */
87
84
  declare const OPTIONAL_THEME_DECLARATIONS: readonly ["foreground-subtle", "foreground-disabled"];
88
85
  type OptionalThemeDeclaration = (typeof OPTIONAL_THEME_DECLARATIONS)[number];
@@ -100,7 +97,7 @@ declare function boardThemeToCss(theme: ThemeInput | null): string;
100
97
  declare function themeMode(theme: ThemeInput | null): 'light' | 'dark' | 'system';
101
98
  /**
102
99
  * Theme font key → Google Fonts family slug, transcribed from the hosted
103
- * board's `theme-fonts-metadata.ts` (golden-tested against it). The wire's
100
+ * board's `theme-fonts-metadata.ts` (tested against it). The wire's
104
101
  * `typography.fontSans` is an internal KEY (`'source-sans-pro'`), and the
105
102
  * Google family is not always a re-casing of it (`source-sans-pro` →
106
103
  * `Source+Sans+3`) — never build a font request from the raw key.
package/dist/theme.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `@cavuno/board/theme` — board theme → shadcn CSS-variable overrides
3
- * (ADR-0057).
3
+ *.
4
4
  *
5
5
  * The board's stored theme (16 semantic colors × light/dark from
6
6
  * `board.context().theme`) is mapped onto the canonical shadcn token
@@ -8,7 +8,7 @@
8
8
  * contract, two consumers: the dashboard edits the board theme, and agents
9
9
  * restyle through the standard shadcn theme file — both end up in the same
10
10
  * tokens. The hosted board renders the same 16 source colors through its
11
- * own token system; a coverage golden in-monorepo asserts neither side
11
+ * own token system; a coverage golden asserts neither side
12
12
  * silently drops a color key.
13
13
  *
14
14
  * A null theme emits nothing — the app's static default theme applies
@@ -41,8 +41,8 @@ interface ThemeInput {
41
41
  */
42
42
  declare function isSafeThemeColorValue(value: string): boolean;
43
43
  /**
44
- * Email-safe snapshot keys (platform brand snapshot / MIG-04).
45
- * Light-only subset consumed by Convex email branding.
44
+ * Email-safe snapshot keys.
45
+ * Light-only subset consumed by server-rendered email branding.
46
46
  */
47
47
  type EmailSafeSnapshotColorKey = 'buttonPrimary' | 'buttonPrimaryText' | 'background' | 'mutedBackground' | 'border' | 'text' | 'textMuted' | 'brandColor';
48
48
  /**
@@ -53,7 +53,7 @@ type EmailSafeSnapshotColorKey = 'buttonPrimary' | 'buttonPrimaryText' | 'backgr
53
53
  * mutedBackground). Within one CSS property name, multi-`:root` cascade
54
54
  * is last-wins and is resolved before this table is consulted.
55
55
  *
56
- * Additive export for the platform brand-snapshot deriver (MIG-04) —
56
+ * Additive export for the platform brand-snapshot deriver —
57
57
  * keeps the CSS ↔ board contract next to its forward twin.
58
58
  */
59
59
  declare const EMAIL_SAFE_SNAPSHOT_FROM_CSS: {
@@ -62,7 +62,7 @@ declare const EMAIL_SAFE_SNAPSHOT_FROM_CSS: {
62
62
  /**
63
63
  * Board key → CSS custom property name(s) (no `--` prefix).
64
64
  *
65
- * The forward write contract for the builder theme tab (MIG-05) and the
65
+ * The forward write contract for the builder theme tab and the
66
66
  * emission table for `boardThemeToCss` / `tokenLines` — one table, so a
67
67
  * tab edit and a render path cannot drift. When a board key fans out to
68
68
  * several CSS names (e.g. `text` → foreground + card-foreground + …),
@@ -77,12 +77,9 @@ declare const BOARD_COLOR_TO_CSS_TOKENS: {
77
77
  readonly [K in BoardColorKey]: readonly string[];
78
78
  };
79
79
  /**
80
- * CSS custom property names (no `--`) that fan out from *optional*
81
- * ColorTokensSchema keys (`textSubtle`, `textDisabled`). Production
82
- * starter `tokens.css` may omit these declarations; the builder theme
83
- * batch lane SKIPS missing optional declarations rather than escalating
84
- * the whole preset to the model (MIG-05). Required declarations still
85
- * escalate on absence — never invent (L5-B).
80
+ * CSS custom property names (without `--`) backed by optional color tokens.
81
+ * A starter may omit these declarations; required declarations must still
82
+ * be present.
86
83
  */
87
84
  declare const OPTIONAL_THEME_DECLARATIONS: readonly ["foreground-subtle", "foreground-disabled"];
88
85
  type OptionalThemeDeclaration = (typeof OPTIONAL_THEME_DECLARATIONS)[number];
@@ -100,7 +97,7 @@ declare function boardThemeToCss(theme: ThemeInput | null): string;
100
97
  declare function themeMode(theme: ThemeInput | null): 'light' | 'dark' | 'system';
101
98
  /**
102
99
  * Theme font key → Google Fonts family slug, transcribed from the hosted
103
- * board's `theme-fonts-metadata.ts` (golden-tested against it). The wire's
100
+ * board's `theme-fonts-metadata.ts` (tested against it). The wire's
104
101
  * `typography.fontSans` is an internal KEY (`'source-sans-pro'`), and the
105
102
  * Google family is not always a re-casing of it (`source-sans-pro` →
106
103
  * `Source+Sans+3`) — never build a font request from the raw key.
package/dist/theme.js CHANGED
@@ -64,7 +64,7 @@ var EMAIL_SAFE_SNAPSHOT_FROM_CSS = {
64
64
  buttonPrimary: ["primary"],
65
65
  buttonPrimaryText: ["primary-foreground"],
66
66
  background: ["background"],
67
- // muted wins; secondary fills only when --muted is absent (A3).
67
+ // Muted wins; secondary fills only when --muted is absent.
68
68
  mutedBackground: ["muted", "secondary"],
69
69
  border: ["border"],
70
70
  text: ["foreground"],
package/dist/theme.mjs CHANGED
@@ -30,7 +30,7 @@ var EMAIL_SAFE_SNAPSHOT_FROM_CSS = {
30
30
  buttonPrimary: ["primary"],
31
31
  buttonPrimaryText: ["primary-foreground"],
32
32
  background: ["background"],
33
- // muted wins; secondary fills only when --muted is absent (A3).
33
+ // Muted wins; secondary fills only when --muted is absent.
34
34
  mutedBackground: ["muted", "secondary"],
35
35
  border: ["border"],
36
36
  text: ["foreground"],
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The board-chrome copy CATALOG (ADR-0059) — every user-visible string the
2
+ * The board-chrome copy CATALOG — every user-visible string the
3
3
  * registry blocks (and the starter's public routes) render, as a typed
4
4
  * record per board language, beside the salary lexicon it patterns after:
5
5
  * plain strings plus functions-per-key where counts/interpolation demand it.
@@ -32,8 +32,7 @@
32
32
  /**
33
33
  * The public-surfaces label groups (stored `jobBoardSettings.config` group
34
34
  * names) that ride the v1 board context as the `labels` bag. CANONICAL —
35
- * the API's server-side allowlist must list the same names (gated by
36
- * `labelGroupsAlignment.test.ts` in apps/web).
35
+ * the API's server-side allowlist must list the same names.
37
36
  */
38
37
  declare const PUBLIC_LABEL_GROUPS: readonly ["jobCardLabels", "navLabels", "breadcrumbsLabels", "footerLabels", "entityLabels", "jobSearchLabels", "globalPaginationLabels", "blogSharedLabels", "salaryLabels"];
39
38
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The board-chrome copy CATALOG (ADR-0059) — every user-visible string the
2
+ * The board-chrome copy CATALOG — every user-visible string the
3
3
  * registry blocks (and the starter's public routes) render, as a typed
4
4
  * record per board language, beside the salary lexicon it patterns after:
5
5
  * plain strings plus functions-per-key where counts/interpolation demand it.
@@ -32,8 +32,7 @@
32
32
  /**
33
33
  * The public-surfaces label groups (stored `jobBoardSettings.config` group
34
34
  * names) that ride the v1 board context as the `labels` bag. CANONICAL —
35
- * the API's server-side allowlist must list the same names (gated by
36
- * `labelGroupsAlignment.test.ts` in apps/web).
35
+ * the API's server-side allowlist must list the same names.
37
36
  */
38
37
  declare const PUBLIC_LABEL_GROUPS: readonly ["jobCardLabels", "navLabels", "breadcrumbsLabels", "footerLabels", "entityLabels", "jobSearchLabels", "globalPaginationLabels", "blogSharedLabels", "salaryLabels"];
39
38
  /**
@@ -2,7 +2,7 @@ import { R as RouteEntry, a as RouteRole } from './roles-vY0AXhoc.mjs';
2
2
 
3
3
  /**
4
4
  * Runtime well-known endpoint — Request → Response serving ManifestV1
5
- * compiled from the app's enumerated routes (ADR-0090 D5.2; LNK-08).
5
+ * compiled from the app's enumerated routes.
6
6
  *
7
7
  * Pure + isomorphic: no node builtins, no framework imports. The app hands
8
8
  * over RouteEntry[] (or a thunk) computed from its router; this module only
@@ -38,7 +38,7 @@ declare function serializeManifest(manifest: {
38
38
  }): string;
39
39
 
40
40
  /**
41
- * Build-plugin variant of the well-known manifest (ADR-0090 D5.2; LNK-08).
41
+ * Build-plugin variant of the well-known manifest.
42
42
  *
43
43
  * Pure function — no fs imports and no write callback: callers (vite
44
44
  * plugin, starter build hook) own the write of `contents` to `path` under
@@ -62,7 +62,7 @@ type EmitWellKnownManifestResult = {
62
62
  declare function emitWellKnownManifest(config: EmitWellKnownManifestConfig): EmitWellKnownManifestResult;
63
63
 
64
64
  /**
65
- * TanStack route-tree → RouteEntry[] enumerator (LNK-08).
65
+ * TanStack route-tree → RouteEntry[] enumerator.
66
66
  *
67
67
  * board-sdk has NO runtime (or type) dependency on @tanstack/react-router.
68
68
  * The public documented Route shape we walk is structural:
@@ -2,7 +2,7 @@ import { R as RouteEntry, a as RouteRole } from './roles-vY0AXhoc.js';
2
2
 
3
3
  /**
4
4
  * Runtime well-known endpoint — Request → Response serving ManifestV1
5
- * compiled from the app's enumerated routes (ADR-0090 D5.2; LNK-08).
5
+ * compiled from the app's enumerated routes.
6
6
  *
7
7
  * Pure + isomorphic: no node builtins, no framework imports. The app hands
8
8
  * over RouteEntry[] (or a thunk) computed from its router; this module only
@@ -38,7 +38,7 @@ declare function serializeManifest(manifest: {
38
38
  }): string;
39
39
 
40
40
  /**
41
- * Build-plugin variant of the well-known manifest (ADR-0090 D5.2; LNK-08).
41
+ * Build-plugin variant of the well-known manifest.
42
42
  *
43
43
  * Pure function — no fs imports and no write callback: callers (vite
44
44
  * plugin, starter build hook) own the write of `contents` to `path` under
@@ -62,7 +62,7 @@ type EmitWellKnownManifestResult = {
62
62
  declare function emitWellKnownManifest(config: EmitWellKnownManifestConfig): EmitWellKnownManifestResult;
63
63
 
64
64
  /**
65
- * TanStack route-tree → RouteEntry[] enumerator (LNK-08).
65
+ * TanStack route-tree → RouteEntry[] enumerator.
66
66
  *
67
67
  * board-sdk has NO runtime (or type) dependency on @tanstack/react-router.
68
68
  * The public documented Route shape we walk is structural:
@@ -89,7 +89,7 @@ var BOARD_PATHS = {
89
89
  talent: "/talent",
90
90
  employers: "/employers",
91
91
  /**
92
- * Alert-email surfaces (ADR-0090 D1/D4). Promoted out of raw literals in
92
+ * Alert-email surfaces. Promoted out of raw literals in
93
93
  * the job-alerts composer so /go indirection and email composition share
94
94
  * one definition.
95
95
  */
@@ -56,7 +56,7 @@ var BOARD_PATHS = {
56
56
  talent: "/talent",
57
57
  employers: "/employers",
58
58
  /**
59
- * Alert-email surfaces (ADR-0090 D1/D4). Promoted out of raw literals in
59
+ * Alert-email surfaces. Promoted out of raw literals in
60
60
  * the job-alerts composer so /go indirection and email composition share
61
61
  * one definition.
62
62
  */
package/package.json CHANGED
@@ -1,24 +1,56 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "1.44.0",
4
- "description": "Typed isomorphic client for the Cavuno Board API",
3
+ "version": "2.0.1",
4
+ "description": "TypeScript SDK for building headless job boards with the Cavuno Board API",
5
+ "keywords": [
6
+ "api-client",
7
+ "careers-page",
8
+ "cavuno",
9
+ "headless-job-board",
10
+ "hiring",
11
+ "job-board",
12
+ "job-board-api",
13
+ "job-board-sdk",
14
+ "jobs",
15
+ "openapi",
16
+ "recruitment",
17
+ "sdk",
18
+ "sitemap",
19
+ "structured-data",
20
+ "typescript"
21
+ ],
22
+ "homepage": "https://cavuno.com/docs/sdk",
23
+ "bugs": {
24
+ "url": "https://github.com/wollemiahq/cavuno-sdk/issues",
25
+ "email": "support@cavuno.com"
26
+ },
5
27
  "license": "MIT",
6
- "type": "commonjs",
28
+ "author": {
29
+ "name": "Cavuno",
30
+ "email": "support@cavuno.com",
31
+ "url": "https://cavuno.com"
32
+ },
7
33
  "repository": {
8
34
  "type": "git",
9
- "url": "git+https://github.com/wollemiahq/cavuno.git",
10
- "directory": "packages/board-sdk"
35
+ "url": "git+https://github.com/wollemiahq/cavuno-sdk.git"
11
36
  },
12
- "sideEffects": false,
13
- "engines": {
14
- "node": ">=20"
37
+ "bin": {
38
+ "cavuno-board": "./dist/bin.mjs"
15
39
  },
40
+ "files": [
41
+ "dist",
42
+ "skills",
43
+ "LICENSE",
44
+ "TRADEMARKS.md",
45
+ "SECURITY.md",
46
+ "CONTRIBUTING.md",
47
+ "CHANGELOG.md"
48
+ ],
49
+ "type": "commonjs",
50
+ "sideEffects": false,
16
51
  "main": "./dist/index.js",
17
52
  "module": "./dist/index.mjs",
18
53
  "types": "./dist/index.d.ts",
19
- "bin": {
20
- "cavuno-board": "./dist/bin.mjs"
21
- },
22
54
  "exports": {
23
55
  ".": {
24
56
  "import": {
@@ -172,34 +204,10 @@
172
204
  },
173
205
  "./skills/*": "./skills/*"
174
206
  },
175
- "files": [
176
- "dist",
177
- "skills"
178
- ],
207
+ "engines": {
208
+ "node": ">=20"
209
+ },
179
210
  "publishConfig": {
180
211
  "access": "public"
181
- },
182
- "scripts": {
183
- "build": "rm -rf dist && tsup",
184
- "clean": "git clean -xdf .turbo dist node_modules src/generated",
185
- "typecheck": "tsgo --noEmit && tsgo --noEmit -p tsconfig.node.json",
186
- "test": "vitest run",
187
- "check:publish": "publint --strict && attw --pack . --profile node16",
188
- "gen:types": "tsx scripts/gen-types.ts",
189
- "check:types": "OPENAPI_URL=spec/openapi.snapshot.json tsx scripts/gen-types.ts && git diff --exit-code -- src/generated/openapi-types.ts",
190
- "gen:skills-manifest": "tsx scripts/generate-skills-manifest.ts",
191
- "assert-publish-target": "node -e \"const p=require('./package.json'); if(p.name!=='@cavuno/board'){throw new Error('Refusing to publish: package.json name is '+p.name+', expected @cavuno/board')}; if(p.private){throw new Error('Refusing to publish: package.json has private:true')}\"",
192
- "prepublishOnly": "pnpm run assert-publish-target && pnpm run gen:skills-manifest && pnpm run build"
193
- },
194
- "devDependencies": {
195
- "@arethetypeswrong/cli": "^0.18.2",
196
- "@kit/data-remote": "workspace:*",
197
- "@kit/tsconfig": "workspace:*",
198
- "@types/node": "catalog:",
199
- "openapi-typescript": "^7.6.0",
200
- "publint": "^0.3.12",
201
- "tsup": "^8.4.0",
202
- "tsx": "^4.19.2",
203
- "vitest": "^2.1.9"
204
212
  }
205
213
  }
@@ -78,8 +78,7 @@ export const board = createBoardClient({
78
78
  ```ts snippet
79
79
  const data = await board.client.fetch<{ object: 'list'; data: unknown[] }>(
80
80
  '/some-new-endpoint',
81
- { query: { limit: 5 } },
82
- );
81
+ { query: { limit: 5 } });
83
82
  ```
84
83
 
85
84
  ## Checklist
@@ -6,7 +6,7 @@ description: The canonical listing-filter vocabulary and URL search-param parsin
6
6
  # Filters: vocabulary + URL parsing
7
7
 
8
8
  `@cavuno/board/filters` is the one filter vocabulary every tenant frontend
9
- shares — the seniority set is golden-tested against the platform source, and
9
+ shares — the seniority set is tested against the platform source, and
10
10
  URL parsing follows the hosted semantics (hand-typed URLs are messy; parsing
11
11
  never throws).
12
12
 
@@ -69,7 +69,7 @@ const sorts = sortLabels(language); // English defaults on every locale
69
69
  Seniority renders as a MULTI-select (hosted parity). `EMPLOYMENT_TYPES`
70
70
  deliberately offers 5 of the 7 wire values (`volunteer`/`other` exist on
71
71
  jobs but are not filter options). `JOB_SORTS` deliberately excludes
72
- `oldest` (ADR-0048); `relevance` is the featured-ranked default.
72
+ `oldest`; `relevance` is the featured-ranked default.
73
73
 
74
74
  ## Load category, skill, and keyword options
75
75
 
@@ -6,7 +6,7 @@ description: Display formatting for board frontends with @cavuno/board/format
6
6
  # Format: board-language display text
7
7
 
8
8
  `@cavuno/board/format` turns wire values into the exact display text the
9
- hosted board renders — golden-tested against the hosted formatters, so a
9
+ hosted board renders — tested against the hosted formatters, so a
10
10
  tenant frontend cannot drift from the platform's rendering rules.
11
11
 
12
12
  ## When to use
@@ -23,7 +23,7 @@ So there are two separate things:
23
23
  2. **`⊕ board.context().labels`** — the operator's per-board overrides,
24
24
  API-served (e.g. `featuredLabel` → "Top Job").
25
25
  3. **`⊕ generated code`** — per-board copy the AI builder ejects to native
26
- code (ADR-0059 layer 3). Supersedes the catalog for that board.
26
+ code. Supersedes the catalog for that board.
27
27
 
28
28
  Every surface resolves copy through **one seam module** (`src/copy.ts`),
29
29
  never by calling the catalog inline:
@@ -62,7 +62,7 @@ extra locales are prefixed (`/de/`, `/fr/`).
62
62
  from `getLocale()` (it replaces the static `board.language` in the root).
63
63
  5. **Seam.** Point `boardCopy` at the URL locale (`getLocale()`) instead of
64
64
  only `board.language`, so `/de/` renders German chrome even on an English
65
- board. This is the opt-in that ADR-0063 adds over the single-language model.
65
+ board. This is the opt-in that adds over the single-language model.
66
66
  6. **SEO slice.** Per-locale `hreflang`, canonical, and sitemap entries are
67
67
  part of completing multi-language — do them when you add real locales, not
68
68
  in the foundation.
@@ -78,5 +78,5 @@ extra locales are prefixed (`/de/`, `/fr/`).
78
78
  - **Do not scatter catalog calls** through markup — everything imports the one
79
79
  seam, so the catalog→code migration is a single-file change.
80
80
 
81
- Reference: ADR-0063 (starter i18n), ADR-0059 (copy catalog), ADR-0010 (entity
81
+ Reference: (starter i18n), (copy catalog), (entity
82
82
  translation). Wiring flavor: `cavuno-board-tanstack-start`.
@@ -5,7 +5,7 @@ description: Build the anonymous "Post a job" funnel with the @cavuno/board SDK
5
5
 
6
6
  # Job posting: the anonymous submission funnel
7
7
 
8
- The no-account "Post a job" wizard (ADR-0042): pick a plan, upload a logo, submit — then branch on the status-discriminated result. Anonymous by design (no board-user token) and rate-limited server-side.
8
+ The no-account "Post a job" wizard: pick a plan, upload a logo, submit — then branch on the status-discriminated result. Anonymous by design (no board-user token) and rate-limited server-side.
9
9
 
10
10
  Out of scope — do not invent exports: the `checkout` branch returns a Stripe Checkout **URL** — the full-page redirect is host-app-owned, and the webhook publishes the job after payment. The SDK ships no Stripe code and no publish/confirm method for the paid path.
11
11
 
@@ -5,7 +5,7 @@ description: Build the board-user messaging inbox with the @cavuno/board SDK —
5
5
 
6
6
  # Messaging: the polled inbox
7
7
 
8
- Employer↔candidate direct messaging for signed-in board users. The v1 transport is **polled REST by design (ADR-0053)** — there is no realtime primitive; near-live UX comes from re-fetching on an interval (3–5s is the reference cadence).
8
+ Employer↔candidate direct messaging for signed-in board users. The v1 transport is **polled REST by design** — there is no realtime primitive; near-live UX comes from re-fetching on an interval (3–5s is the reference cadence).
9
9
 
10
10
  Out of scope — do not invent exports: no websockets, no SSE, no `subscribe`/`onMessage` — polling `list` / `listMessages` / `unreadCount` IS the contract.
11
11
 
@@ -62,8 +62,7 @@ convo.viewerLastReadMessageId; // my last-read pointer (null = never)
62
62
 
63
63
  const { data: messages } = await board.me.conversations.listMessages(
64
64
  conversationId,
65
- { limit: 50 },
66
- );
65
+ { limit: 50 });
67
66
  for (const m of messages) {
68
67
  m.body; // '' when unsent (tombstone)
69
68
  m.readAt; // read receipt — when the recipient read it, or null
@@ -5,7 +5,7 @@ description: Build the candidate job-access paywall with the @cavuno/board SDK
5
5
 
6
6
  # Candidate paywall: offers, checkout, grant
7
7
 
8
- The candidate-facing money flow (doc 36 / ADR-0056): anonymous pricing, gated job lists, and an embedded Stripe checkout that ends in an access grant.
8
+ The candidate-facing money flow: anonymous pricing, gated job lists, and an embedded Stripe checkout that ends in an access grant.
9
9
 
10
10
  Out of scope — do not invent exports: the SDK is Stripe-agnostic. It returns a *mount kit*; loading Stripe.js (`loadStripe`, `initEmbeddedCheckout`) and every redirect is host-app-owned. There is no SDK helper that mounts, redirects, or handles webhooks.
11
11
 
@@ -76,7 +76,7 @@ const skillsInBerlin = await board.salaries.locations.skills('berlin');
76
76
 
77
77
  ## Never recompute salary math
78
78
 
79
- Render the returned aggregates **as-is**. Do not average mins and maxes, derive medians from percentiles, sum across rails, or convert currency client-side — every response quotes one board `currency` and the weighted math (averages, medians, p25/p75 bands, per-seniority splits) is done server-side against the full sample. Client-side arithmetic will disagree with the hosted board and other consumers.
79
+ Render the returned aggregates **as-is**. Do not average mins and maxes, derive medians from percentiles, sum across rails, or convert currency client-side — every response quotes one board `currency` and the weighted math is done server-side against the full sample. Client-side arithmetic will disagree with the hosted board and other consumers.
80
80
 
81
81
  ## Verify
82
82
 
@@ -6,7 +6,7 @@ description: Structured data + head builders for board frontends with @cavuno/bo
6
6
  # SEO: structured data + head builders
7
7
 
8
8
  `@cavuno/board/seo` emits the exact structured data the hosted board emits —
9
- golden-tested against the hosted builders, so a tenant frontend gets Google
9
+ tested against the hosted builders, so a tenant frontend gets Google
10
10
  for Jobs, breadcrumb, blog, and salary rich results without reinventing (or
11
11
  drifting from) the platform's rules. Render every builder's output into a
12
12
  `<script type="application/ld+json">` tag; builders return `null` when there
@@ -62,8 +62,7 @@ const trail = createBreadcrumbJsonLd(
62
62
  { label: 'Jobs', href: '/jobs' },
63
63
  { label: job.title }, // current page — no href
64
64
  ],
65
- { origin: 'https://jobs.example.com' },
66
- );
65
+ { origin: 'https://jobs.example.com' });
67
66
  ```
68
67
 
69
68
  ## Blog Article + author ProfilePage
@@ -100,7 +99,7 @@ The board language is a REQUIRED leading parameter wherever display strings
100
99
  are produced (no `en` default). The money formatters are USD-hardcoded —
101
100
  the hosted salary-page quirk, kept deliberately; the locale drives number
102
101
  formatting only. The FAQ ships TEMPLATED English sentences (board-custom
103
- FAQ copy is a tracked API gap and will supersede it).
102
+ FAQ copy is a not currently available and will supersede it).
104
103
 
105
104
  ```ts snippet
106
105
  import {
@@ -117,8 +116,7 @@ const detail = await board.salaries.titles.retrieve('software-engineer');
117
116
 
118
117
  const occupation = titleSalaryJsonLd(language, detail);
119
118
  const faq = faqJsonLd(
120
- buildSalaryFaq(language, detail.categoryName, detail.overallSalary),
121
- );
119
+ buildSalaryFaq(language, detail.categoryName, detail.overallSalary));
122
120
  // Index pages: itemListJsonLd(items); on-page figures: formatRange(language, min, max)
123
121
  // and sortBySeniority(detail.bySeniority) for the ladder table.
124
122
  ```
@@ -141,7 +141,7 @@ the stale cookie with `clearGrantCookie()`.
141
141
  ## Open-redirect guards
142
142
 
143
143
  The `/password?redirect=` round-trip is the classic open-redirect hole.
144
- `safeRedirectPath` transcribes the hosted board's guard (golden-tested
144
+ `safeRedirectPath` transcribes the hosted board's guard (tested
145
145
  against it): same-origin absolute paths pass through, everything else —
146
146
  `//evil.com`, full URLs, `javascript:`, backslash and control-character
147
147
  normalization bypasses — collapses to `'/'`.
@@ -18,7 +18,8 @@ This skill is the orchestrator. Work top to bottom, delegating each surface to i
18
18
  ## When not to use
19
19
 
20
20
  - Authoring the hosted board inside the Cavuno admin (that's the operator Puck builder, not the SDK).
21
- - Building the operator/admin REST API client — that's `@kit/api-client`, not `@cavuno/board`.
21
+ - Building operator automation — use the public `cavuno` CLI or REST API;
22
+ `@cavuno/board` is for visitor-facing board experiences.
22
23
 
23
24
  ## Inspect the app
24
25
 
@@ -8,7 +8,7 @@ description: Build the board's sitemap with @cavuno/board/sitemap — the hosted
8
8
  `@cavuno/board/sitemap` ships the hosted board's sitemap architecture: a
9
9
  sitemap INDEX at `/sitemap.xml` pointing at one file per content bucket,
10
10
  each an ordinary `<urlset>`. The XML byte layout and the bucket rules are
11
- golden-tested against the hosted implementation, so a custom frontend's
11
+ tested against the hosted implementation, so a custom frontend's
12
12
  sitemap corpus lines up bucket-for-bucket with what cavuno.com would emit.
13
13
 
14
14
  Two tiers, use both: