@cavuno/board 4.64.0 → 4.65.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 (47) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/{_spec-D1Qg_Twd.d.mts → _spec-CIufstif.d.mts} +57 -1
  3. package/dist/{_spec-D1Qg_Twd.d.ts → _spec-CIufstif.d.ts} +57 -1
  4. package/dist/{blog-Dp2jAVVM.d.ts → blog-DuNJLfIh.d.ts} +1 -1
  5. package/dist/{blog-e0YbZBjg.d.mts → blog-teDJ9KaO.d.mts} +1 -1
  6. package/dist/{board-Cc3wbTKI.d.mts → board-DZNCHGgl.d.mts} +2 -2
  7. package/dist/{board-BeNZLOYC.d.ts → board-iCHYuNhr.d.ts} +2 -2
  8. package/dist/{breadcrumbs-C5WjB8jm.d.mts → breadcrumbs-Bt3oNIAx.d.mts} +2 -2
  9. package/dist/{breadcrumbs-BOFeIYEX.d.ts → breadcrumbs-DYGo0yB9.d.ts} +2 -2
  10. package/dist/browser/cavuno-board.global.min.js +1 -1
  11. package/dist/chunk-RDHHRDKN.mjs +6 -0
  12. package/dist/doctor.js +1 -1
  13. package/dist/filters.d.mts +2 -2
  14. package/dist/filters.d.ts +2 -2
  15. package/dist/format.d.mts +4 -4
  16. package/dist/format.d.ts +4 -4
  17. package/dist/index.d.mts +15 -14
  18. package/dist/index.d.ts +15 -14
  19. package/dist/index.js +1 -1
  20. package/dist/index.mjs +4 -4
  21. package/dist/{jobs-CClqlUld.d.mts → jobs-CbXbDBij.d.mts} +1 -1
  22. package/dist/{jobs-D04ngjCP.d.ts → jobs-DM_QMccX.d.ts} +1 -1
  23. package/dist/mcp.d.mts +52 -0
  24. package/dist/mcp.d.ts +52 -0
  25. package/dist/mcp.js +150 -0
  26. package/dist/mcp.mjs +128 -0
  27. package/dist/{search-DZeNdYN6.d.ts → search-B7x4qt9A.d.ts} +1 -1
  28. package/dist/{search-BtrwcLkc.d.mts → search-PrqcJMft.d.mts} +1 -1
  29. package/dist/{seo-DLoyZRTo.d.ts → seo-C1Br7ygq.d.ts} +1 -1
  30. package/dist/seo-files.d.mts +2 -2
  31. package/dist/seo-files.d.ts +2 -2
  32. package/dist/{seo-LfpgbdnO.d.mts → seo-ohehUCzN.d.mts} +1 -1
  33. package/dist/seo.d.mts +22 -7
  34. package/dist/seo.d.ts +22 -7
  35. package/dist/seo.js +12 -3
  36. package/dist/seo.mjs +12 -3
  37. package/dist/server.d.mts +6 -6
  38. package/dist/server.d.ts +6 -6
  39. package/dist/sitemap.d.mts +6 -6
  40. package/dist/sitemap.d.ts +6 -6
  41. package/dist/skills.js +1 -1
  42. package/dist/suggest.d.mts +2 -2
  43. package/dist/suggest.d.ts +2 -2
  44. package/package.json +13 -2
  45. package/skills/cavuno-board-mcp/SKILL.md +80 -0
  46. package/skills/cavuno-board-seo/BLOG.md +13 -8
  47. package/skills/manifest.json +8 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  This changelog records changes that affect Board API compatibility, exported
4
4
  types, runtime behavior, or supported integration patterns.
5
5
 
6
+ ## 4.65.0 — 2026-11-09
7
+
8
+ - Board MCP server: every board on a plan with API access serves a public,
9
+ read-only MCP server that AI assistants can use to search its jobs and
10
+ companies. The Board API answers it at `POST /boards/{identifier}/mcp`,
11
+ with a setup page at `GET /boards/{identifier}/mcp/docs`, an MCP Server
12
+ Card at `GET /boards/{identifier}/mcp/server-card` and an AI Catalog at
13
+ `GET /boards/{identifier}/mcp/ai-catalog`.
14
+ - New entry point `@cavuno/board/mcp` with `createMcpHandler({ board })`,
15
+ which serves the board's MCP server on your own domain. Mount it at
16
+ `/mcp`, `/mcp/*` and `/.well-known/ai-catalog.json`; any other path
17
+ below `/mcp` answers 404.
18
+ - `board.context()` returns `features.mcp`, true when the board serves its
19
+ MCP server, so a frontend can link to its setup page.
20
+ - `GET /subscribers/count` returns `subscribers`, the count shown on the
21
+ dashboard: unique people who currently receive job alerts, job matches
22
+ or both.
23
+ - A marketing suppression's `reason` can be `spam_report`.
24
+ - `GET /boards/{identifier}/blog/posts` returns `count`, the total published
25
+ posts in the list across every page, for the whole blog, one tag or one
26
+ author. Pass it as `totalPosts` to `createAuthorProfileJsonLd`.
27
+ - `createBlogArticleJsonLd` takes `authorProfileUrl`, the first author's
28
+ profile page URL. The Article `author` then carries the same `@id` and
29
+ `url` as the `Person` that `createAuthorProfileJsonLd` declares on that
30
+ page.
31
+
6
32
  ## 4.64.0 — 2026-11-05
7
33
 
8
34
  - Tip jar: tippers can cover the card fee. `board.tipJar.get` returns
@@ -225,6 +225,26 @@ interface components {
225
225
  /** @description The board-access grant. Send it as the `X-Board-Access` header on subsequent content reads to pass the password wall. */
226
226
  token: string;
227
227
  };
228
+ /** @description An AI Catalog listing the board's MCP Server Card, for discovery from the board's domain alone. */
229
+ BoardAiCatalog: {
230
+ /**
231
+ * @description The AI Catalog format version.
232
+ * @enum {string}
233
+ */
234
+ specVersion: "1.0";
235
+ /** @description One entry: the board's MCP server. */
236
+ entries: {
237
+ /** @description The server's catalog identifier, `urn:air:<host>:mcp:jobs`, where `<host>` is the board's public host without a leading `www.`. */
238
+ identifier: string;
239
+ /**
240
+ * @description The entry is an MCP Server Card.
241
+ * @enum {string}
242
+ */
243
+ type: "application/mcp-server-card+json";
244
+ /** @description Where to fetch the Server Card: `/mcp/server-card` on the board's own host. */
245
+ url: string;
246
+ }[];
247
+ };
228
248
  BoardAuthConsumeMagicLinkBody: {
229
249
  token: string;
230
250
  };
@@ -408,6 +428,40 @@ interface components {
408
428
  definition: components["schemas"]["CustomFieldDefinition"];
409
429
  };
410
430
  BoardJobFormField: components["schemas"]["BoardFormBuiltinField"] | components["schemas"]["BoardJobFormCustomField"] | components["schemas"]["BoardJobFormCollectionField"];
431
+ /** @description An MCP Server Card (SEP-2127): what an assistant needs to find and connect to the server before it connects. It lists no tools; `tools/list` on the server does. */
432
+ BoardMcpServerCard: {
433
+ /** @description The Server Card JSON Schema this document follows: `https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`. */
434
+ $schema: string;
435
+ /** @description The server's name in reverse-DNS form, from the board's public host: `jobs.example.com` is `com.example.jobs/jobs`. A leading `www.` is dropped. */
436
+ name: string;
437
+ /** @description The server version, the same one `initialize` reports in `serverInfo`. */
438
+ version: string;
439
+ /** @description The board name, cut to 100 characters. */
440
+ title?: string;
441
+ /** @description What the server does, in at most 100 characters. */
442
+ description: string;
443
+ /** @description The server's setup page on the board's host, `/mcp/docs`. */
444
+ websiteUrl: string;
445
+ /** @description The board's square app icons when it has them, otherwise its logo. Absent when the board has neither. */
446
+ icons?: {
447
+ /** @description Absolute URL of the icon image. */
448
+ src: string;
449
+ /** @description The image type, when known (`image/png`). */
450
+ mimeType?: string;
451
+ /** @description The pixel sizes, when known (`512x512`). */
452
+ sizes?: string[];
453
+ }[];
454
+ /** @description Where to connect: one Streamable HTTP endpoint. */
455
+ remotes: {
456
+ /**
457
+ * @description The transport: stateless Streamable HTTP.
458
+ * @enum {string}
459
+ */
460
+ type: "streamable-http";
461
+ /** @description The server URL, `/mcp` on the board's own host. */
462
+ url: string;
463
+ }[];
464
+ };
411
465
  BoardProfileFormCollectionField: {
412
466
  /**
413
467
  * @description discriminator enum property added by openapi-typescript
@@ -2219,7 +2273,7 @@ interface components {
2219
2273
  status: "granted" | "withdrawn";
2220
2274
  source: string;
2221
2275
  /** @enum {string|null} */
2222
- reason: "person_request" | "operator_request" | "account_deleted" | null;
2276
+ reason: "person_request" | "operator_request" | "account_deleted" | "spam_report" | null;
2223
2277
  /** Format: date-time */
2224
2278
  grantedAt: string | null;
2225
2279
  /** Format: date-time */
@@ -2826,6 +2880,8 @@ interface components {
2826
2880
  contactPage: boolean;
2827
2881
  /** @description Whether `GET /v1/boards/{identifier}/places/suggest` suggests any place on this board (cities, towns and suburbs beyond the board's own places). When `false` it returns an empty list: offer only the board's places (`GET /places?q=`) and do not call it. */
2828
2882
  placeSuggestions: boolean;
2883
+ /** @description Whether the board serves its public MCP server, which AI assistants connect to at `/mcp` on the board's own host, with a setup page for job seekers at `/mcp/docs`. `true` on a paid board that is not password-protected and has not turned the server off. Show a link to `/mcp/docs` (for example in the footer) only when `true`. */
2884
+ mcp: boolean;
2829
2885
  };
2830
2886
  /**
2831
2887
  * @description How the operator charges employers for the candidate directory. `paid_messaging` leaves profiles fully visible and spends a credit on a first cold message; `paid_unlocks_and_messaging` also redacts directory cards and gates the opaque `/p/{id}` profile route behind an unlock credit. `null` means the operator has not chosen explicitly, in which case infer it from the published `talent_access` plans: any plan granting profile unlocks means `paid_unlocks_and_messaging`, otherwise `paid_messaging`. The paywall is inert regardless when the board publishes no talent plan. An anonymous viewer has no entitlement read to derive this from, so it ships here rather than only on `me/talent-access`.
@@ -225,6 +225,26 @@ interface components {
225
225
  /** @description The board-access grant. Send it as the `X-Board-Access` header on subsequent content reads to pass the password wall. */
226
226
  token: string;
227
227
  };
228
+ /** @description An AI Catalog listing the board's MCP Server Card, for discovery from the board's domain alone. */
229
+ BoardAiCatalog: {
230
+ /**
231
+ * @description The AI Catalog format version.
232
+ * @enum {string}
233
+ */
234
+ specVersion: "1.0";
235
+ /** @description One entry: the board's MCP server. */
236
+ entries: {
237
+ /** @description The server's catalog identifier, `urn:air:<host>:mcp:jobs`, where `<host>` is the board's public host without a leading `www.`. */
238
+ identifier: string;
239
+ /**
240
+ * @description The entry is an MCP Server Card.
241
+ * @enum {string}
242
+ */
243
+ type: "application/mcp-server-card+json";
244
+ /** @description Where to fetch the Server Card: `/mcp/server-card` on the board's own host. */
245
+ url: string;
246
+ }[];
247
+ };
228
248
  BoardAuthConsumeMagicLinkBody: {
229
249
  token: string;
230
250
  };
@@ -408,6 +428,40 @@ interface components {
408
428
  definition: components["schemas"]["CustomFieldDefinition"];
409
429
  };
410
430
  BoardJobFormField: components["schemas"]["BoardFormBuiltinField"] | components["schemas"]["BoardJobFormCustomField"] | components["schemas"]["BoardJobFormCollectionField"];
431
+ /** @description An MCP Server Card (SEP-2127): what an assistant needs to find and connect to the server before it connects. It lists no tools; `tools/list` on the server does. */
432
+ BoardMcpServerCard: {
433
+ /** @description The Server Card JSON Schema this document follows: `https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`. */
434
+ $schema: string;
435
+ /** @description The server's name in reverse-DNS form, from the board's public host: `jobs.example.com` is `com.example.jobs/jobs`. A leading `www.` is dropped. */
436
+ name: string;
437
+ /** @description The server version, the same one `initialize` reports in `serverInfo`. */
438
+ version: string;
439
+ /** @description The board name, cut to 100 characters. */
440
+ title?: string;
441
+ /** @description What the server does, in at most 100 characters. */
442
+ description: string;
443
+ /** @description The server's setup page on the board's host, `/mcp/docs`. */
444
+ websiteUrl: string;
445
+ /** @description The board's square app icons when it has them, otherwise its logo. Absent when the board has neither. */
446
+ icons?: {
447
+ /** @description Absolute URL of the icon image. */
448
+ src: string;
449
+ /** @description The image type, when known (`image/png`). */
450
+ mimeType?: string;
451
+ /** @description The pixel sizes, when known (`512x512`). */
452
+ sizes?: string[];
453
+ }[];
454
+ /** @description Where to connect: one Streamable HTTP endpoint. */
455
+ remotes: {
456
+ /**
457
+ * @description The transport: stateless Streamable HTTP.
458
+ * @enum {string}
459
+ */
460
+ type: "streamable-http";
461
+ /** @description The server URL, `/mcp` on the board's own host. */
462
+ url: string;
463
+ }[];
464
+ };
411
465
  BoardProfileFormCollectionField: {
412
466
  /**
413
467
  * @description discriminator enum property added by openapi-typescript
@@ -2219,7 +2273,7 @@ interface components {
2219
2273
  status: "granted" | "withdrawn";
2220
2274
  source: string;
2221
2275
  /** @enum {string|null} */
2222
- reason: "person_request" | "operator_request" | "account_deleted" | null;
2276
+ reason: "person_request" | "operator_request" | "account_deleted" | "spam_report" | null;
2223
2277
  /** Format: date-time */
2224
2278
  grantedAt: string | null;
2225
2279
  /** Format: date-time */
@@ -2826,6 +2880,8 @@ interface components {
2826
2880
  contactPage: boolean;
2827
2881
  /** @description Whether `GET /v1/boards/{identifier}/places/suggest` suggests any place on this board (cities, towns and suburbs beyond the board's own places). When `false` it returns an empty list: offer only the board's places (`GET /places?q=`) and do not call it. */
2828
2882
  placeSuggestions: boolean;
2883
+ /** @description Whether the board serves its public MCP server, which AI assistants connect to at `/mcp` on the board's own host, with a setup page for job seekers at `/mcp/docs`. `true` on a paid board that is not password-protected and has not turned the server off. Show a link to `/mcp/docs` (for example in the footer) only when `true`. */
2884
+ mcp: boolean;
2829
2885
  };
2830
2886
  /**
2831
2887
  * @description How the operator charges employers for the candidate directory. `paid_messaging` leaves profiles fully visible and spends a credit on a first cold message; `paid_unlocks_and_messaging` also redacts directory cards and gates the opaque `/p/{id}` profile route behind an unlock credit. `null` means the operator has not chosen explicitly, in which case infer it from the published `talent_access` plans: any plan granting profile unlocks means `paid_unlocks_and_messaging`, otherwise `paid_messaging`. The paywall is inert regardless when the board publishes no talent plan. An anonymous viewer has no entitlement read to derive this from, so it ships here rather than only on `me/talent-access`.
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-D1Qg_Twd.js';
1
+ import { S as Schemas } from './_spec-CIufstif.js';
2
2
 
3
3
  /** Author shape embedded on posts (no `object` discriminator). */
4
4
  type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-D1Qg_Twd.mjs';
1
+ import { S as Schemas } from './_spec-CIufstif.mjs';
2
2
 
3
3
  /** Author shape embedded on posts (no `object` discriminator). */
4
4
  type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
@@ -1,5 +1,5 @@
1
- import { S as Schemas } from './_spec-D1Qg_Twd.mjs';
2
- import { L as ListEnvelope, v as RelatedSearch, b as CustomFieldFilter, O as ObjectReferenceFilter, a as JobCapability } from './jobs-CClqlUld.mjs';
1
+ import { S as Schemas } from './_spec-CIufstif.mjs';
2
+ import { L as ListEnvelope, v as RelatedSearch, b as CustomFieldFilter, O as ObjectReferenceFilter, a as JobCapability } from './jobs-CbXbDBij.mjs';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { S as Schemas } from './_spec-D1Qg_Twd.js';
2
- import { L as ListEnvelope, v as RelatedSearch, b as CustomFieldFilter, O as ObjectReferenceFilter, a as JobCapability } from './jobs-D04ngjCP.js';
1
+ import { S as Schemas } from './_spec-CIufstif.js';
2
+ import { L as ListEnvelope, v as RelatedSearch, b as CustomFieldFilter, O as ObjectReferenceFilter, a as JobCapability } from './jobs-DM_QMccX.js';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-Cc3wbTKI.mjs';
2
- import { P as PublicJob } from './jobs-CClqlUld.mjs';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-DZNCHGgl.mjs';
2
+ import { P as PublicJob } from './jobs-CbXbDBij.mjs';
3
3
 
4
4
  /**
5
5
  * Wire enum for `salaryTimeframe`. Defined here (not re-exported from any
@@ -1,5 +1,5 @@
1
- import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-BeNZLOYC.js';
2
- import { P as PublicJob } from './jobs-D04ngjCP.js';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-iCHYuNhr.js';
2
+ import { P as PublicJob } from './jobs-DM_QMccX.js';
3
3
 
4
4
  /**
5
5
  * Wire enum for `salaryTimeframe`. Defined here (not re-exported from any