@cavuno/board 2.0.0 → 2.0.2
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.
- package/CHANGELOG.md +26 -0
- package/CONTRIBUTING.md +25 -0
- package/LICENSE +21 -0
- package/README.md +12 -7
- package/SECURITY.md +28 -0
- package/TRADEMARKS.md +16 -0
- package/dist/_spec-sW85fuvT.d.mts +2731 -0
- package/dist/_spec-sW85fuvT.d.ts +2731 -0
- package/dist/bin.mjs +16 -348
- package/dist/{board-B8tJGX4i.d.ts → board-DKXyxwNN.d.ts} +2 -2
- package/dist/{board-DmRuCA8m.d.mts → board-QFeHT4UN.d.mts} +2 -2
- package/dist/doctor.d.mts +6 -19
- package/dist/doctor.d.ts +6 -19
- package/dist/doctor.js +16 -344
- package/dist/doctor.mjs +15 -343
- package/dist/filters.d.mts +5 -5
- package/dist/filters.d.ts +5 -5
- package/dist/format.d.mts +17 -19
- package/dist/format.d.ts +17 -19
- package/dist/go.d.mts +2 -2
- package/dist/go.d.ts +2 -2
- package/dist/go.js +1 -1
- package/dist/go.mjs +1 -1
- package/dist/index.d.mts +16 -18
- package/dist/index.d.ts +16 -18
- package/dist/index.js +39 -28
- package/dist/index.mjs +39 -28
- package/dist/{jobs-BEYJY97F.d.ts → jobs-CuRzTDb1.d.mts} +15 -13
- package/dist/{jobs-DJiISpqX.d.mts → jobs-DTnCZGtb.d.ts} +15 -13
- package/dist/paths.d.mts +6 -6
- package/dist/paths.d.ts +6 -6
- package/dist/paths.js +1 -1
- package/dist/paths.mjs +1 -1
- package/dist/roles-vY0AXhoc.d.mts +3 -3
- package/dist/roles-vY0AXhoc.d.ts +3 -3
- package/dist/route-contract.d.mts +16 -16
- package/dist/route-contract.d.ts +16 -16
- package/dist/route-contract.js +1 -1
- package/dist/route-contract.mjs +1 -1
- package/dist/{salaries-D6q7h1J6.d.ts → salaries-BOpR51Ny.d.mts} +3 -3
- package/dist/{salaries-B_Xb5k2s.d.mts → salaries-QoNpzRCT.d.ts} +3 -3
- package/dist/{search-CnOIZEuc.d.ts → search-B5ROY6PK.d.ts} +2 -2
- package/dist/{search-uC_ijbdu.d.mts → search-f93nrSg3.d.mts} +2 -2
- package/dist/seo.d.mts +17 -18
- package/dist/seo.d.ts +17 -18
- package/dist/server.d.mts +14 -32
- package/dist/server.d.ts +14 -32
- package/dist/sitemap.d.mts +7 -7
- package/dist/sitemap.d.ts +7 -7
- package/dist/sitemap.js +4 -2
- package/dist/sitemap.mjs +4 -2
- package/dist/skills.d.mts +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/dist/theme.d.mts +10 -13
- package/dist/theme.d.ts +10 -13
- package/dist/theme.js +1 -1
- package/dist/theme.mjs +1 -1
- package/dist/{ui-copy-CKfFTtLk.d.mts → ui-copy-CL-VN1xb.d.mts} +2 -3
- package/dist/{ui-copy-CKfFTtLk.d.ts → ui-copy-CL-VN1xb.d.ts} +2 -3
- package/dist/well-known.d.mts +3 -3
- package/dist/well-known.d.ts +3 -3
- package/dist/well-known.js +1 -1
- package/dist/well-known.mjs +1 -1
- package/package.json +46 -38
- package/skills/cavuno-board-client/SKILL.md +1 -2
- package/skills/cavuno-board-filters/SKILL.md +2 -2
- package/skills/cavuno-board-format/SKILL.md +1 -1
- package/skills/cavuno-board-i18n/SKILL.md +3 -4
- package/skills/cavuno-board-job-posting/SKILL.md +1 -1
- package/skills/cavuno-board-messaging/SKILL.md +2 -3
- package/skills/cavuno-board-paywall/SKILL.md +1 -1
- package/skills/cavuno-board-salaries/SKILL.md +1 -1
- package/skills/cavuno-board-seo/SKILL.md +4 -6
- package/skills/cavuno-board-server/SKILL.md +1 -1
- package/skills/cavuno-board-setup/SKILL.md +2 -1
- package/skills/cavuno-board-sitemap/SKILL.md +1 -1
- package/skills/cavuno-board-smoke-test/SKILL.md +4 -13
- package/skills/flavors/tanstack-start/SKILL.md +1 -2
- package/skills/manifest.json +1 -1
- package/dist/_spec-C7vqY_b3.d.mts +0 -5202
- package/dist/_spec-C7vqY_b3.d.ts +0 -5202
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
|
|
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(
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
package/dist/suggest.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SuggestionItem, a as SearchSuggestQuery, F as FetchOptions, b as SuggestResult } from './search-
|
|
2
|
-
import './_spec-
|
|
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-
|
|
2
|
-
import './_spec-
|
|
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
|
-
|
|
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
|
|
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
|
|
45
|
-
* Light-only subset consumed by
|
|
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
|
|
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
|
|
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 (
|
|
81
|
-
*
|
|
82
|
-
*
|
|
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` (
|
|
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
|
-
|
|
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
|
|
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
|
|
45
|
-
* Light-only subset consumed by
|
|
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
|
|
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
|
|
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 (
|
|
81
|
-
*
|
|
82
|
-
*
|
|
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` (
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
/**
|
package/dist/well-known.d.mts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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:
|
package/dist/well-known.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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:
|
package/dist/well-known.js
CHANGED
|
@@ -89,7 +89,7 @@ var BOARD_PATHS = {
|
|
|
89
89
|
talent: "/talent",
|
|
90
90
|
employers: "/employers",
|
|
91
91
|
/**
|
|
92
|
-
* Alert-email surfaces
|
|
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
|
*/
|
package/dist/well-known.mjs
CHANGED
|
@@ -56,7 +56,7 @@ var BOARD_PATHS = {
|
|
|
56
56
|
talent: "/talent",
|
|
57
57
|
employers: "/employers",
|
|
58
58
|
/**
|
|
59
|
-
* Alert-email surfaces
|
|
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": "2.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.2",
|
|
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": "hi@cavuno.com"
|
|
26
|
+
},
|
|
5
27
|
"license": "MIT",
|
|
6
|
-
"
|
|
28
|
+
"author": {
|
|
29
|
+
"name": "Cavuno",
|
|
30
|
+
"email": "hi@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
|
-
"
|
|
13
|
-
|
|
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
|
-
"
|
|
176
|
-
"
|
|
177
|
-
|
|
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
|
}
|
|
@@ -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
|
|
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
|
|
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 —
|
|
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
|
|
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
|
|
65
|
+
board. This is the opt-in 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,4 @@ 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
|
-
|
|
82
|
-
translation). Wiring flavor: `cavuno-board-tanstack-start`.
|
|
81
|
+
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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:
|