@cavuno/board 4.18.0 → 4.20.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 (45) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/{_spec-Dk0TIRUc.d.mts → _spec-CyNKpM_j.d.mts} +90 -4
  3. package/dist/{_spec-Dk0TIRUc.d.ts → _spec-CyNKpM_j.d.ts} +90 -4
  4. package/dist/{blog-C04NWTh_.d.mts → blog-BNIqGayD.d.mts} +1 -1
  5. package/dist/{blog-1THfucKR.d.ts → blog-CRvaDyzJ.d.ts} +1 -1
  6. package/dist/{board-CqeoQAa1.d.ts → board-CXNxSlUB.d.ts} +24 -4
  7. package/dist/{board-DIO9aFXx.d.mts → board-mn3GVbrC.d.mts} +24 -4
  8. package/dist/{breadcrumbs-mE9Zsxlq.d.mts → breadcrumbs-Bi4LHNAF.d.mts} +2 -2
  9. package/dist/{breadcrumbs-CCT1oC2-.d.ts → breadcrumbs-Crk6Q69T.d.ts} +2 -2
  10. package/dist/browser/cavuno-board.global.min.js +1 -1
  11. package/dist/{chunk-2WBQVVOB.mjs → chunk-NQTMFOKF.mjs} +2 -100
  12. package/dist/chunk-Z4ALWIGS.mjs +101 -0
  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 +63 -18
  18. package/dist/index.d.ts +63 -18
  19. package/dist/index.js +31 -7
  20. package/dist/index.mjs +41 -16
  21. package/dist/{jobs-CVmAWGtJ.d.mts → jobs-CALE3I8I.d.mts} +1 -1
  22. package/dist/{jobs-Dvv0vX8p.d.ts → jobs-CSWXqLZR.d.ts} +1 -1
  23. package/dist/route-contract.d.mts +2 -1
  24. package/dist/route-contract.d.ts +2 -1
  25. package/dist/{search-CcstbHOe.d.ts → search-BRCbe1Nm.d.ts} +1 -1
  26. package/dist/{search-BJ5myYaf.d.mts → search-B_hwS-xu.d.mts} +1 -1
  27. package/dist/{seo-Ds6tLMqU.d.mts → seo-CS4lrG20.d.mts} +1 -1
  28. package/dist/{seo-CWO6N-iE.d.ts → seo-D1u-RmLQ.d.ts} +1 -1
  29. package/dist/seo-files.d.mts +2 -2
  30. package/dist/seo-files.d.ts +2 -2
  31. package/dist/seo.d.mts +6 -6
  32. package/dist/seo.d.ts +6 -6
  33. package/dist/server.d.mts +6 -6
  34. package/dist/server.d.ts +6 -6
  35. package/dist/server.mjs +4 -2
  36. package/dist/sitemap.d.mts +15 -7
  37. package/dist/sitemap.d.ts +15 -7
  38. package/dist/sitemap.js +49 -4
  39. package/dist/sitemap.mjs +44 -4
  40. package/dist/suggest.d.mts +2 -2
  41. package/dist/suggest.d.ts +2 -2
  42. package/dist/well-known.d.mts +2 -1
  43. package/dist/well-known.d.ts +2 -1
  44. package/package.json +2 -2
  45. package/skills/manifest.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,43 @@
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.20.0 — 2026-09-03
7
+
8
+ - **Memberships as public identity.** `PublicCompanyMembership` (`planId` +
9
+ display name) is exported, and `board.companies.list({ membershipPlanId })`
10
+ scopes the roster to the companies holding an active membership on that
11
+ published plan. Combines with `marketSlug` by intersection; `count` then
12
+ describes the members.
13
+ - **`board.plans.list({ purpose })`** accepts every plan purpose:
14
+ `job_posting`, `talent_access`, `membership`, `job_seeker`,
15
+ `employer_service`, `job_seeker_service`. Plans carry `pricingMode`; a
16
+ `contact` plan is quote-only, so render `priceText` and the CTA fields
17
+ instead of `price`.
18
+ - **`board.plans.listSalesLed()` is deprecated.** Use
19
+ `plans.list({ purpose: 'employer_service' })` and keep the rows whose
20
+ `pricingMode` is `contact`. The helper keeps working as a compatibility
21
+ read.
22
+ - **`BOARD_API_ERROR_CODES`**: adds `membership_required`, returned when a
23
+ board requires an approved membership to post and the caller has none.
24
+
25
+ ## 4.19.0 — 2026-09-02
26
+
27
+ - **`board.sitemap()` / `board.sitemap.entries(bucket, { limit, cursor })`**:
28
+ new namespace over `GET /sitemap` and `GET /sitemap/{bucket}`. The board
29
+ publishes its complete sitemap — every bucket with an entry count, and each
30
+ bucket's board-relative `path` + `lastModified` entries, cursor-paged up to
31
+ 1000 per page — so a headless frontend reproduces the hosted sitemap exactly
32
+ (cross-axis salary pages, jobs place × category / skill pages, markets)
33
+ without enumerating the catalog itself.
34
+ - **`@cavuno/board/sitemap` walker**: `listedBuckets` and `buildBucketUrls`
35
+ now read the published sitemap first and fall back to the previous
36
+ per-family enumeration only when the API answers 404. A sitemap build drops
37
+ from ~25 catalog reads to a handful of cached reads. All existing exports
38
+ are unchanged.
39
+ - **`board.companies.markets({ cursor })`**: the unsearched market list is
40
+ now paginated (`hasMore` / `nextCursor` are real; use `paginate()`). With
41
+ `search` it remains a top-N preview. `CompanyMarketsListQuery` gains `cursor`.
42
+
6
43
  ## 4.18.0 — 2026-09-02
7
44
 
8
45
  - **`board.auth.requestMagicLink({ intent: 'sign_in' })`**: new optional
@@ -295,6 +295,20 @@ interface components {
295
295
  name: string;
296
296
  };
297
297
  };
298
+ BoardSitemap: {
299
+ /** @enum {string} */
300
+ object: "board_sitemap";
301
+ /** @description The buckets the board publishes, in the canonical bucket order. Empty buckets are omitted — exactly the set the hosted `/sitemap.xml` index lists. */
302
+ buckets: components["schemas"]["BoardSitemapBucketSummary"][];
303
+ };
304
+ BoardSitemapBucketSummary: {
305
+ /** @description Bucket name — pass it to `GET /boards/:identifier/sitemap/{bucket}` to read its entries. */
306
+ bucket: string;
307
+ /** @description Number of entries in the bucket. */
308
+ count: number;
309
+ /** @description ISO 8601 timestamp of the newest content in the bucket, when the board tracks one. */
310
+ lastModified?: string;
311
+ };
298
312
  BoardUser: {
299
313
  /** @description Board user ID. */
300
314
  id: string;
@@ -533,6 +547,7 @@ interface components {
533
547
  publishedJobCount: number;
534
548
  /** @description Number of jobs that contribute to this company's salary aggregates on the board (the salary sample size). `0` when there is no usable salary data — prefer this over fetching the full company-salary document just to decide whether to show a Salaries tab. Not the same as `publishedJobCount` (open roles without pay data stay at 0 here). */
535
549
  salarySampleCount: number;
550
+ membership: components["schemas"]["PublicCompanyMembership"];
536
551
  links: components["schemas"]["PublicCompanyLinks"];
537
552
  };
538
553
  CompanyPublicDetail: components["schemas"]["CompanyPublic"] & {
@@ -906,7 +921,9 @@ interface components {
906
921
  /** @enum {string} */
907
922
  object: "employer_billing_option";
908
923
  /** @enum {string} */
909
- type: "subscription" | "order";
924
+ type: "subscription" | "order" | "plan_assignment";
925
+ /** @enum {string} */
926
+ kind?: "member_post";
910
927
  planId: string;
911
928
  planName: string;
912
929
  /** @enum {string} */
@@ -915,6 +932,10 @@ interface components {
915
932
  jobsTotal: number;
916
933
  featuredRemaining: number;
917
934
  featuredTotal: number;
935
+ /** @description True when this option grants unlimited job posts; jobsRemaining/jobsTotal are then not meaningful. */
936
+ jobsUnlimited?: boolean;
937
+ /** @description True when this option grants unlimited featured posts. */
938
+ featuredUnlimited?: boolean;
918
939
  /**
919
940
  * Format: date-time
920
941
  * @description When a subscription renews, or `null` for one-time orders.
@@ -946,6 +967,11 @@ interface components {
946
967
  type: "subscription";
947
968
  planId: string;
948
969
  id: string;
970
+ } | {
971
+ /** @enum {string} */
972
+ type: "plan_assignment";
973
+ planId?: string;
974
+ id?: string;
949
975
  };
950
976
  invoiceBilling?: {
951
977
  billingName?: string;
@@ -1225,6 +1251,16 @@ interface components {
1225
1251
  hidden: boolean;
1226
1252
  position: number;
1227
1253
  };
1254
+ EmployerPostingCapabilities: {
1255
+ canPost: boolean;
1256
+ /** @enum {string} */
1257
+ reason?: "membership_required";
1258
+ discountPercent: number;
1259
+ freePostsRemaining: number;
1260
+ /** @description True when an active membership grants unlimited posts. */
1261
+ freePostsUnlimited?: boolean;
1262
+ memberPlanName?: string;
1263
+ };
1228
1264
  EmployerProfileStats: {
1229
1265
  /** @enum {string} */
1230
1266
  object: "employer_profile_stats";
@@ -1678,13 +1714,26 @@ interface components {
1678
1714
  /** @description Authoring default: the operator's prose description in the board's language. The localized public string lives in the board template — compose it from `featureSummary`, `billingInterval`, and `talent` rather than displaying this verbatim on localized surfaces. */
1679
1715
  description: string | null;
1680
1716
  /** @enum {string} */
1681
- purpose: "job_posting" | "talent_access";
1717
+ purpose: "job_posting" | "talent_access" | "membership" | "job_seeker" | "employer_service" | "job_seeker_service";
1682
1718
  /** @enum {string} */
1683
1719
  kind: "free" | "subscription" | "one_time" | "bundle";
1684
1720
  /** @enum {string|null} */
1685
- billingInterval: "month" | "year" | null;
1721
+ billingInterval: "day" | "week" | "month" | "year" | null;
1722
+ /** @description Stripe recurring.interval_count. Null means 1. Quarterly is month × 3. */
1723
+ billingIntervalCount: number | null;
1686
1724
  isRecommended: boolean;
1687
1725
  displayOrder: number;
1726
+ /**
1727
+ * @description How the plan is sold. `priced` is bought with `price.stripePriceId`; `contact` is quote-only and must render the CTA below instead of a price. Read this, never `price` — a contact plan can still carry a zeroed price row. Plans created before this field existed report `priced`.
1728
+ * @enum {string}
1729
+ */
1730
+ pricingMode: "priced" | "contact";
1731
+ /** @description Operator-authored display price for a contact plan, e.g. "From $2,000" or "15% of first-year salary". Null when unset. */
1732
+ priceText: string | null;
1733
+ /** @description Operator-authored CTA label for a contact plan. Null when unset; supply your own wording. */
1734
+ ctaText: string | null;
1735
+ /** @description The CTA target: an https, mailto:, or tel: URL. Null when unset, in which case render no CTA rather than a dead control. */
1736
+ ctaDestination: string | null;
1688
1737
  invoiceOnly: boolean;
1689
1738
  /** @enum {string|null} */
1690
1739
  publishTiming: "on_issue" | "on_payment" | null;
@@ -1695,6 +1744,10 @@ interface components {
1695
1744
  /** @description The public Stripe Price id used to start checkout. */
1696
1745
  stripePriceId: string | null;
1697
1746
  } | null;
1747
+ /**
1748
+ * @deprecated
1749
+ * @description Job-posting feature summary. **Deprecated** — superseded by `features`, which carries the same benefits keyed by canonical feature key. Still serialized for compatibility.
1750
+ */
1698
1751
  featureSummary: {
1699
1752
  durationDays: number;
1700
1753
  maxActiveJobs: number;
@@ -1702,11 +1755,23 @@ interface components {
1702
1755
  /** @enum {string} */
1703
1756
  featureSelectionMode: "auto" | "manual";
1704
1757
  };
1705
- /** @description Talent-access allowances (per billing period). Present only when `purpose` is `talent_access`. `"unlimited"` is a sentinel value. */
1758
+ /**
1759
+ * @deprecated
1760
+ * @description Talent-access allowances (per billing period). Present only when `purpose` is `talent_access`. `"unlimited"` is a sentinel value. **Deprecated** — superseded by `features`, which carries the same allowances keyed by canonical feature key. Still serialized for compatibility.
1761
+ */
1706
1762
  talent?: {
1707
1763
  unlocksPerPeriod: string;
1708
1764
  messagesPerPeriod: string;
1709
1765
  };
1766
+ /** @description Self-describing map of every benefit the plan carries, keyed by the canonical feature key. Each entry includes the value and enough of the feature definition (name, dataType, and optional displayOrder) to render without a second call. Values are strings; the literal "unlimited" is a sentinel and must be kept as a string. New features, including operator-defined custom attributes, appear here with no schema change. The API returns no display copy. */
1767
+ features: {
1768
+ [key: string]: {
1769
+ value: string;
1770
+ name: string;
1771
+ dataType: string;
1772
+ displayOrder?: number;
1773
+ };
1774
+ };
1710
1775
  };
1711
1776
  PostSuggestion: {
1712
1777
  /** @enum {string} */
@@ -1849,6 +1914,11 @@ interface components {
1849
1914
  * @enum {string|null}
1850
1915
  */
1851
1916
  talentAccessModel: "paid_messaging" | "paid_unlocks_and_messaging" | null;
1917
+ /** @description Employer posting policy. Separate from `features.publicJobSubmission`, which says whether the board takes public submissions at all — this says who may complete one. */
1918
+ posting: {
1919
+ /** @description Whether posting a job on this board requires an active membership. When `true`, render the join gate in place of the anonymous post form: the platform rejects a create from a company with no contributing assignment (`membership_required`). Absent board config defaults to `false`. This flag is board policy and is safe to read anonymously; a signed-in employer's own standing rides their company billing options. */
1920
+ requiresMembership: boolean;
1921
+ };
1852
1922
  analytics: {
1853
1923
  ga4MeasurementId: string | null;
1854
1924
  gtmId: string | null;
@@ -1958,6 +2028,13 @@ interface components {
1958
2028
  */
1959
2029
  public: string | null;
1960
2030
  };
2031
+ /** @description The company's membership on this board, or `null` when it holds none that is public. Only an ACTIVE assignment on a PUBLISHED plan whose purpose is membership appears here: a company on a private (operator-only) plan reads as `null`, and non-membership purchases — job-posting packs, talent access, services — never appear. Identity only: entitlements, billing state, and expiry are not on the public wire. */
2032
+ PublicCompanyMembership: {
2033
+ /** @description The membership plan's `id`. Pass it to `GET /boards/{identifier}/companies?membershipPlanId=` to browse the roster, or join it against the board's plans to render the plan's own copy. */
2034
+ planId: string;
2035
+ /** @description The membership plan's current display name — the badge text. Operators rename plans, so treat `planId` as the stable key. */
2036
+ planName: string;
2037
+ } | null;
1961
2038
  PublicJob: {
1962
2039
  /** @description Unique identifier for the object. Use this value as the `{id}` path parameter for the job endpoints (e.g. `GET /v1/jobs/{id}`). */
1963
2040
  id: string;
@@ -2419,6 +2496,7 @@ interface components {
2419
2496
  jobCount: number;
2420
2497
  currency: string;
2421
2498
  };
2499
+ /** @description Deprecated. Prefer public plans with purpose employer_service and pricingMode contact. */
2422
2500
  SalesLedPlan: {
2423
2501
  /** @enum {string} */
2424
2502
  object: "sales_led_plan";
@@ -2451,6 +2529,14 @@ interface components {
2451
2529
  /** Format: email */
2452
2530
  workEmail: string;
2453
2531
  };
2532
+ SitemapEntry: {
2533
+ /** @enum {string} */
2534
+ object: "sitemap_entry";
2535
+ /** @description Board-relative path, always starting with `/`. Prefix it with your own origin to build the absolute URL — the API never returns the hosted origin. */
2536
+ path: string;
2537
+ /** @description ISO 8601 timestamp of the entry, when one is known. */
2538
+ lastModified?: string;
2539
+ };
2454
2540
  SkillLocationSalary: {
2455
2541
  /** @enum {string} */
2456
2542
  object: "skill_location_salary";
@@ -295,6 +295,20 @@ interface components {
295
295
  name: string;
296
296
  };
297
297
  };
298
+ BoardSitemap: {
299
+ /** @enum {string} */
300
+ object: "board_sitemap";
301
+ /** @description The buckets the board publishes, in the canonical bucket order. Empty buckets are omitted — exactly the set the hosted `/sitemap.xml` index lists. */
302
+ buckets: components["schemas"]["BoardSitemapBucketSummary"][];
303
+ };
304
+ BoardSitemapBucketSummary: {
305
+ /** @description Bucket name — pass it to `GET /boards/:identifier/sitemap/{bucket}` to read its entries. */
306
+ bucket: string;
307
+ /** @description Number of entries in the bucket. */
308
+ count: number;
309
+ /** @description ISO 8601 timestamp of the newest content in the bucket, when the board tracks one. */
310
+ lastModified?: string;
311
+ };
298
312
  BoardUser: {
299
313
  /** @description Board user ID. */
300
314
  id: string;
@@ -533,6 +547,7 @@ interface components {
533
547
  publishedJobCount: number;
534
548
  /** @description Number of jobs that contribute to this company's salary aggregates on the board (the salary sample size). `0` when there is no usable salary data — prefer this over fetching the full company-salary document just to decide whether to show a Salaries tab. Not the same as `publishedJobCount` (open roles without pay data stay at 0 here). */
535
549
  salarySampleCount: number;
550
+ membership: components["schemas"]["PublicCompanyMembership"];
536
551
  links: components["schemas"]["PublicCompanyLinks"];
537
552
  };
538
553
  CompanyPublicDetail: components["schemas"]["CompanyPublic"] & {
@@ -906,7 +921,9 @@ interface components {
906
921
  /** @enum {string} */
907
922
  object: "employer_billing_option";
908
923
  /** @enum {string} */
909
- type: "subscription" | "order";
924
+ type: "subscription" | "order" | "plan_assignment";
925
+ /** @enum {string} */
926
+ kind?: "member_post";
910
927
  planId: string;
911
928
  planName: string;
912
929
  /** @enum {string} */
@@ -915,6 +932,10 @@ interface components {
915
932
  jobsTotal: number;
916
933
  featuredRemaining: number;
917
934
  featuredTotal: number;
935
+ /** @description True when this option grants unlimited job posts; jobsRemaining/jobsTotal are then not meaningful. */
936
+ jobsUnlimited?: boolean;
937
+ /** @description True when this option grants unlimited featured posts. */
938
+ featuredUnlimited?: boolean;
918
939
  /**
919
940
  * Format: date-time
920
941
  * @description When a subscription renews, or `null` for one-time orders.
@@ -946,6 +967,11 @@ interface components {
946
967
  type: "subscription";
947
968
  planId: string;
948
969
  id: string;
970
+ } | {
971
+ /** @enum {string} */
972
+ type: "plan_assignment";
973
+ planId?: string;
974
+ id?: string;
949
975
  };
950
976
  invoiceBilling?: {
951
977
  billingName?: string;
@@ -1225,6 +1251,16 @@ interface components {
1225
1251
  hidden: boolean;
1226
1252
  position: number;
1227
1253
  };
1254
+ EmployerPostingCapabilities: {
1255
+ canPost: boolean;
1256
+ /** @enum {string} */
1257
+ reason?: "membership_required";
1258
+ discountPercent: number;
1259
+ freePostsRemaining: number;
1260
+ /** @description True when an active membership grants unlimited posts. */
1261
+ freePostsUnlimited?: boolean;
1262
+ memberPlanName?: string;
1263
+ };
1228
1264
  EmployerProfileStats: {
1229
1265
  /** @enum {string} */
1230
1266
  object: "employer_profile_stats";
@@ -1678,13 +1714,26 @@ interface components {
1678
1714
  /** @description Authoring default: the operator's prose description in the board's language. The localized public string lives in the board template — compose it from `featureSummary`, `billingInterval`, and `talent` rather than displaying this verbatim on localized surfaces. */
1679
1715
  description: string | null;
1680
1716
  /** @enum {string} */
1681
- purpose: "job_posting" | "talent_access";
1717
+ purpose: "job_posting" | "talent_access" | "membership" | "job_seeker" | "employer_service" | "job_seeker_service";
1682
1718
  /** @enum {string} */
1683
1719
  kind: "free" | "subscription" | "one_time" | "bundle";
1684
1720
  /** @enum {string|null} */
1685
- billingInterval: "month" | "year" | null;
1721
+ billingInterval: "day" | "week" | "month" | "year" | null;
1722
+ /** @description Stripe recurring.interval_count. Null means 1. Quarterly is month × 3. */
1723
+ billingIntervalCount: number | null;
1686
1724
  isRecommended: boolean;
1687
1725
  displayOrder: number;
1726
+ /**
1727
+ * @description How the plan is sold. `priced` is bought with `price.stripePriceId`; `contact` is quote-only and must render the CTA below instead of a price. Read this, never `price` — a contact plan can still carry a zeroed price row. Plans created before this field existed report `priced`.
1728
+ * @enum {string}
1729
+ */
1730
+ pricingMode: "priced" | "contact";
1731
+ /** @description Operator-authored display price for a contact plan, e.g. "From $2,000" or "15% of first-year salary". Null when unset. */
1732
+ priceText: string | null;
1733
+ /** @description Operator-authored CTA label for a contact plan. Null when unset; supply your own wording. */
1734
+ ctaText: string | null;
1735
+ /** @description The CTA target: an https, mailto:, or tel: URL. Null when unset, in which case render no CTA rather than a dead control. */
1736
+ ctaDestination: string | null;
1688
1737
  invoiceOnly: boolean;
1689
1738
  /** @enum {string|null} */
1690
1739
  publishTiming: "on_issue" | "on_payment" | null;
@@ -1695,6 +1744,10 @@ interface components {
1695
1744
  /** @description The public Stripe Price id used to start checkout. */
1696
1745
  stripePriceId: string | null;
1697
1746
  } | null;
1747
+ /**
1748
+ * @deprecated
1749
+ * @description Job-posting feature summary. **Deprecated** — superseded by `features`, which carries the same benefits keyed by canonical feature key. Still serialized for compatibility.
1750
+ */
1698
1751
  featureSummary: {
1699
1752
  durationDays: number;
1700
1753
  maxActiveJobs: number;
@@ -1702,11 +1755,23 @@ interface components {
1702
1755
  /** @enum {string} */
1703
1756
  featureSelectionMode: "auto" | "manual";
1704
1757
  };
1705
- /** @description Talent-access allowances (per billing period). Present only when `purpose` is `talent_access`. `"unlimited"` is a sentinel value. */
1758
+ /**
1759
+ * @deprecated
1760
+ * @description Talent-access allowances (per billing period). Present only when `purpose` is `talent_access`. `"unlimited"` is a sentinel value. **Deprecated** — superseded by `features`, which carries the same allowances keyed by canonical feature key. Still serialized for compatibility.
1761
+ */
1706
1762
  talent?: {
1707
1763
  unlocksPerPeriod: string;
1708
1764
  messagesPerPeriod: string;
1709
1765
  };
1766
+ /** @description Self-describing map of every benefit the plan carries, keyed by the canonical feature key. Each entry includes the value and enough of the feature definition (name, dataType, and optional displayOrder) to render without a second call. Values are strings; the literal "unlimited" is a sentinel and must be kept as a string. New features, including operator-defined custom attributes, appear here with no schema change. The API returns no display copy. */
1767
+ features: {
1768
+ [key: string]: {
1769
+ value: string;
1770
+ name: string;
1771
+ dataType: string;
1772
+ displayOrder?: number;
1773
+ };
1774
+ };
1710
1775
  };
1711
1776
  PostSuggestion: {
1712
1777
  /** @enum {string} */
@@ -1849,6 +1914,11 @@ interface components {
1849
1914
  * @enum {string|null}
1850
1915
  */
1851
1916
  talentAccessModel: "paid_messaging" | "paid_unlocks_and_messaging" | null;
1917
+ /** @description Employer posting policy. Separate from `features.publicJobSubmission`, which says whether the board takes public submissions at all — this says who may complete one. */
1918
+ posting: {
1919
+ /** @description Whether posting a job on this board requires an active membership. When `true`, render the join gate in place of the anonymous post form: the platform rejects a create from a company with no contributing assignment (`membership_required`). Absent board config defaults to `false`. This flag is board policy and is safe to read anonymously; a signed-in employer's own standing rides their company billing options. */
1920
+ requiresMembership: boolean;
1921
+ };
1852
1922
  analytics: {
1853
1923
  ga4MeasurementId: string | null;
1854
1924
  gtmId: string | null;
@@ -1958,6 +2028,13 @@ interface components {
1958
2028
  */
1959
2029
  public: string | null;
1960
2030
  };
2031
+ /** @description The company's membership on this board, or `null` when it holds none that is public. Only an ACTIVE assignment on a PUBLISHED plan whose purpose is membership appears here: a company on a private (operator-only) plan reads as `null`, and non-membership purchases — job-posting packs, talent access, services — never appear. Identity only: entitlements, billing state, and expiry are not on the public wire. */
2032
+ PublicCompanyMembership: {
2033
+ /** @description The membership plan's `id`. Pass it to `GET /boards/{identifier}/companies?membershipPlanId=` to browse the roster, or join it against the board's plans to render the plan's own copy. */
2034
+ planId: string;
2035
+ /** @description The membership plan's current display name — the badge text. Operators rename plans, so treat `planId` as the stable key. */
2036
+ planName: string;
2037
+ } | null;
1961
2038
  PublicJob: {
1962
2039
  /** @description Unique identifier for the object. Use this value as the `{id}` path parameter for the job endpoints (e.g. `GET /v1/jobs/{id}`). */
1963
2040
  id: string;
@@ -2419,6 +2496,7 @@ interface components {
2419
2496
  jobCount: number;
2420
2497
  currency: string;
2421
2498
  };
2499
+ /** @description Deprecated. Prefer public plans with purpose employer_service and pricingMode contact. */
2422
2500
  SalesLedPlan: {
2423
2501
  /** @enum {string} */
2424
2502
  object: "sales_led_plan";
@@ -2451,6 +2529,14 @@ interface components {
2451
2529
  /** Format: email */
2452
2530
  workEmail: string;
2453
2531
  };
2532
+ SitemapEntry: {
2533
+ /** @enum {string} */
2534
+ object: "sitemap_entry";
2535
+ /** @description Board-relative path, always starting with `/`. Prefix it with your own origin to build the absolute URL — the API never returns the hosted origin. */
2536
+ path: string;
2537
+ /** @description ISO 8601 timestamp of the entry, when one is known. */
2538
+ lastModified?: string;
2539
+ };
2454
2540
  SkillLocationSalary: {
2455
2541
  /** @enum {string} */
2456
2542
  object: "skill_location_salary";
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-Dk0TIRUc.mjs';
1
+ import { S as Schemas } from './_spec-CyNKpM_j.mjs';
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-Dk0TIRUc.js';
1
+ import { S as Schemas } from './_spec-CyNKpM_j.js';
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-Dk0TIRUc.js';
2
- import { L as ListEnvelope, m as RelatedSearch } from './jobs-Dvv0vX8p.js';
1
+ import { S as Schemas } from './_spec-CyNKpM_j.js';
2
+ import { L as ListEnvelope, m as RelatedSearch } from './jobs-CSWXqLZR.js';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /** A market (sector) a company operates in — name + its source slug. */
@@ -29,10 +29,23 @@ type CompanyCategorySalary = Schemas['CompanyCategorySalary'];
29
29
  type CompanyListEnvelope = ListEnvelope<PublicCompany> & {
30
30
  relatedSearches?: RelatedSearch[];
31
31
  };
32
+ /**
33
+ * A company's membership on the board, as public identity: the plan's `id`
34
+ * and its current display name. `planId` is the stable key — join it against
35
+ * `board.plans` for price, benefits, and description.
36
+ */
37
+ type PublicCompanyMembership = Schemas['PublicCompanyMembership'];
32
38
  type CompaniesListQuery = {
33
39
  cursor?: string;
34
40
  /** Scope to a single market (sector) by slug. Unknown slugs 404. */
35
41
  marketSlug?: string;
42
+ /**
43
+ * Scope to the companies holding an active membership on this plan, by the
44
+ * plan's `id`. Only published membership plans match — any other id returns
45
+ * an empty list. Combines with `marketSlug` by intersection, and the roster
46
+ * becomes the whole result set, so `count` describes the members.
47
+ */
48
+ membershipPlanId?: string;
36
49
  /** 1–100. */
37
50
  limit?: number;
38
51
  /**
@@ -52,8 +65,15 @@ type CompanySimilarQuery = {
52
65
  };
53
66
  type CompanyMarket = Schemas['CompanyMarket'];
54
67
  type CompanyMarketsListQuery = {
55
- /** 1–200, default 100 (a top-by-company-count preview). */
68
+ /** Page size, 1–200 (default 100). */
56
69
  limit?: number;
70
+ /**
71
+ * Opaque forward cursor from a previous response's `nextCursor`. The
72
+ * unsearched list is fully paginated (walk it with `paginate` to enumerate
73
+ * every market); a `search` call returns one preview page with
74
+ * `hasMore: false`, so the cursor does not apply there.
75
+ */
76
+ cursor?: string;
57
77
  search?: string;
58
78
  };
59
79
  type CompaniesSearchBody = Schemas['PublicCompaniesSearchBody'];
@@ -111,4 +131,4 @@ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
111
131
  type CustomFieldType = CustomFieldDefinition['type'];
112
132
  type CustomFieldOption = Schemas['CustomFieldOption'];
113
133
 
114
- export type { SkillLocationSalary as A, SkillLocationsIndex as B, CustomFieldDefinition as C, TitleLocationSalary as D, TitleLocationsIndex as E, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CompanySalarySummary as l, CustomFieldOption as m, CustomFieldType as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBoardAds as q, PublicBoardAnalytics as r, PublicBoardFeatures as s, PublicBoardJobForm as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
134
+ export type { SalaryTitle as A, SkillLocationSalary as B, CustomFieldDefinition as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CompanySalarySummary as l, CustomFieldOption as m, CustomFieldType as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBoardAds as q, PublicBoardAnalytics as r, PublicBoardFeatures as s, PublicBoardJobForm as t, PublicCompany as u, PublicCompanyDetail as v, PublicCompanyMembership as w, SalaryCompany as x, SalaryLocation as y, SalarySkill as z };
@@ -1,5 +1,5 @@
1
- import { S as Schemas } from './_spec-Dk0TIRUc.mjs';
2
- import { L as ListEnvelope, m as RelatedSearch } from './jobs-CVmAWGtJ.mjs';
1
+ import { S as Schemas } from './_spec-CyNKpM_j.mjs';
2
+ import { L as ListEnvelope, m as RelatedSearch } from './jobs-CALE3I8I.mjs';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /** A market (sector) a company operates in — name + its source slug. */
@@ -29,10 +29,23 @@ type CompanyCategorySalary = Schemas['CompanyCategorySalary'];
29
29
  type CompanyListEnvelope = ListEnvelope<PublicCompany> & {
30
30
  relatedSearches?: RelatedSearch[];
31
31
  };
32
+ /**
33
+ * A company's membership on the board, as public identity: the plan's `id`
34
+ * and its current display name. `planId` is the stable key — join it against
35
+ * `board.plans` for price, benefits, and description.
36
+ */
37
+ type PublicCompanyMembership = Schemas['PublicCompanyMembership'];
32
38
  type CompaniesListQuery = {
33
39
  cursor?: string;
34
40
  /** Scope to a single market (sector) by slug. Unknown slugs 404. */
35
41
  marketSlug?: string;
42
+ /**
43
+ * Scope to the companies holding an active membership on this plan, by the
44
+ * plan's `id`. Only published membership plans match — any other id returns
45
+ * an empty list. Combines with `marketSlug` by intersection, and the roster
46
+ * becomes the whole result set, so `count` describes the members.
47
+ */
48
+ membershipPlanId?: string;
36
49
  /** 1–100. */
37
50
  limit?: number;
38
51
  /**
@@ -52,8 +65,15 @@ type CompanySimilarQuery = {
52
65
  };
53
66
  type CompanyMarket = Schemas['CompanyMarket'];
54
67
  type CompanyMarketsListQuery = {
55
- /** 1–200, default 100 (a top-by-company-count preview). */
68
+ /** Page size, 1–200 (default 100). */
56
69
  limit?: number;
70
+ /**
71
+ * Opaque forward cursor from a previous response's `nextCursor`. The
72
+ * unsearched list is fully paginated (walk it with `paginate` to enumerate
73
+ * every market); a `search` call returns one preview page with
74
+ * `hasMore: false`, so the cursor does not apply there.
75
+ */
76
+ cursor?: string;
57
77
  search?: string;
58
78
  };
59
79
  type CompaniesSearchBody = Schemas['PublicCompaniesSearchBody'];
@@ -111,4 +131,4 @@ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
111
131
  type CustomFieldType = CustomFieldDefinition['type'];
112
132
  type CustomFieldOption = Schemas['CustomFieldOption'];
113
133
 
114
- export type { SkillLocationSalary as A, SkillLocationsIndex as B, CustomFieldDefinition as C, TitleLocationSalary as D, TitleLocationsIndex as E, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CompanySalarySummary as l, CustomFieldOption as m, CustomFieldType as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBoardAds as q, PublicBoardAnalytics as r, PublicBoardFeatures as s, PublicBoardJobForm as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
134
+ export type { SalaryTitle as A, SkillLocationSalary as B, CustomFieldDefinition as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanyCategorySalary as a, CompanySalary as b, CompaniesListQuery as c, CompanyListEnvelope as d, CompaniesSearchBody as e, CompanyJobsListQuery as f, CompanySimilarQuery as g, CompanyMarketsListQuery as h, SalaryDetailQuery as i, CompanyMarket as j, CompanyMarketRef as k, CompanySalarySummary as l, CustomFieldOption as m, CustomFieldType as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBoardAds as q, PublicBoardAnalytics as r, PublicBoardFeatures as s, PublicBoardJobForm as t, PublicCompany as u, PublicCompanyDetail as v, PublicCompanyMembership as w, SalaryCompany as x, SalaryLocation as y, SalarySkill as z };
@@ -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-DIO9aFXx.mjs';
2
- import { P as PublicJob } from './jobs-CVmAWGtJ.mjs';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-mn3GVbrC.mjs';
2
+ import { P as PublicJob } from './jobs-CALE3I8I.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-CqeoQAa1.js';
2
- import { P as PublicJob } from './jobs-Dvv0vX8p.js';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-CXNxSlUB.js';
2
+ import { P as PublicJob } from './jobs-CSWXqLZR.js';
3
3
 
4
4
  /**
5
5
  * Wire enum for `salaryTimeframe`. Defined here (not re-exported from any