@cavuno/board 4.69.0 → 4.71.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 +54 -0
  2. package/dist/{_spec-CFOj7Qdf.d.mts → _spec-OPrym0QJ.d.mts} +83 -2
  3. package/dist/{_spec-CFOj7Qdf.d.ts → _spec-OPrym0QJ.d.ts} +83 -2
  4. package/dist/{blog-BaVJi3q1.d.ts → blog-BlRb84MY.d.ts} +1 -1
  5. package/dist/{blog-DCRBPnpZ.d.mts → blog-CHQYIhHH.d.mts} +1 -1
  6. package/dist/{board-DMS3I3sJ.d.mts → board-Btc1dzQB.d.mts} +2 -2
  7. package/dist/{board-zLt7j6hj.d.ts → board-D74R4Iml.d.ts} +2 -2
  8. package/dist/{breadcrumbs-yGijUUtR.d.ts → breadcrumbs-Bv76gXvF.d.ts} +2 -2
  9. package/dist/{breadcrumbs-Dwf0yq7B.d.mts → breadcrumbs-CSm6P79s.d.mts} +2 -2
  10. package/dist/browser/cavuno-board.global.min.js +1 -1
  11. package/dist/{chunk-7SAHE7UW.mjs → chunk-AQD4OMX4.mjs} +4 -0
  12. package/dist/filters.d.mts +2 -2
  13. package/dist/filters.d.ts +2 -2
  14. package/dist/format.d.mts +4 -4
  15. package/dist/format.d.ts +4 -4
  16. package/dist/index.d.mts +92 -22
  17. package/dist/index.d.ts +92 -22
  18. package/dist/index.js +66 -8
  19. package/dist/index.mjs +63 -9
  20. package/dist/{jobs-Dz_w1jZq.d.ts → jobs-BMG0vrVI.d.ts} +1 -1
  21. package/dist/{jobs-Cew_q69W.d.mts → jobs-xjE0IrNu.d.mts} +1 -1
  22. package/dist/{search-DwvgvtEg.d.mts → search-BJkiU3Ic.d.mts} +1 -1
  23. package/dist/{search-BqAYR47P.d.ts → search-suUh-E7O.d.ts} +1 -1
  24. package/dist/{seo-CGy4fY5a.d.ts → seo-CW1JjEXH.d.ts} +1 -1
  25. package/dist/{seo-FKj1pSHZ.d.mts → seo-DGdqWPLo.d.mts} +1 -1
  26. package/dist/seo-files.d.mts +2 -2
  27. package/dist/seo-files.d.ts +2 -2
  28. package/dist/seo-files.js +6 -0
  29. package/dist/seo-files.mjs +6 -0
  30. package/dist/seo.d.mts +6 -6
  31. package/dist/seo.d.ts +6 -6
  32. package/dist/server.d.mts +6 -6
  33. package/dist/server.d.ts +6 -6
  34. package/dist/server.mjs +1 -1
  35. package/dist/sitemap.d.mts +6 -6
  36. package/dist/sitemap.d.ts +6 -6
  37. package/dist/sitemap.mjs +1 -1
  38. package/dist/suggest.d.mts +2 -2
  39. package/dist/suggest.d.ts +2 -2
  40. package/package.json +1 -1
  41. package/skills/cavuno-board-account/SKILL.md +16 -0
  42. package/skills/cavuno-board-auth/SKILL.md +3 -0
  43. package/skills/cavuno-board-job-alerts/SKILL.md +12 -0
  44. package/skills/cavuno-board-newsletter/SKILL.md +81 -0
  45. package/skills/manifest.json +8 -1
package/dist/index.js CHANGED
@@ -146,6 +146,8 @@ var BOARD_API_ERROR_CODES = [
146
146
  // Job alerts (anonymous + authenticated)
147
147
  "job_alert_not_found",
148
148
  "job_alerts_disabled",
149
+ "job_alert_confirmation_send_failed",
150
+ "job_alert_email_suppressed",
149
151
  "candidate_alert_limit_reached",
150
152
  "candidate_alert_not_found",
151
153
  // Candidate account
@@ -200,6 +202,8 @@ var BOARD_API_ERROR_CODES = [
200
202
  "employer_not_member",
201
203
  "employer_payment_required",
202
204
  "employer_pipeline_stage_not_found",
205
+ "company_custom_field_not_found",
206
+ "company_custom_field_not_editable",
203
207
  "employer_member_not_found",
204
208
  "employer_invite_not_found",
205
209
  "not_company_admin",
@@ -447,7 +451,7 @@ async function clearSession(storage) {
447
451
  }
448
452
 
449
453
  // src/version.ts
450
- var SDK_VERSION = "4.69.0";
454
+ var SDK_VERSION = "4.71.0";
451
455
 
452
456
  // src/client.ts
453
457
  function isRawBody(body) {
@@ -1411,13 +1415,21 @@ function jobAlertsNamespace(client) {
1411
1415
  body: input
1412
1416
  });
1413
1417
  },
1414
- /** Re-activate a previously unsubscribed subscription via the manage token. */
1418
+ /**
1419
+ * Resume a previously unsubscribed subscription via the manage token.
1420
+ * `status` is `resubscribed`, or `confirmation_sent` when the address
1421
+ * never confirmed: a confirmation email went out and the alerts start
1422
+ * once it is clicked.
1423
+ */
1415
1424
  resubscribe(input, options) {
1416
- return client.fetch("/job-alerts/resubscribe", {
1417
- ...options,
1418
- method: "POST",
1419
- body: input
1420
- });
1425
+ return client.fetch(
1426
+ "/job-alerts/resubscribe",
1427
+ {
1428
+ ...options,
1429
+ method: "POST",
1430
+ body: input
1431
+ }
1432
+ );
1421
1433
  },
1422
1434
  /** Edit a preference's filters/frequency via the manage token. */
1423
1435
  updatePreference(input, options) {
@@ -2263,7 +2275,10 @@ function meNamespace(client) {
2263
2275
  { ...options, method: "PATCH", body }
2264
2276
  );
2265
2277
  },
2266
- /** Retrieve profile custom fields for a company I belong to. */
2278
+ /**
2279
+ * Retrieve profile custom fields for a company I belong to, with the
2280
+ * saved files of upload fields (`customFieldMedia`).
2281
+ */
2267
2282
  retrieveCustomFields(slug, options) {
2268
2283
  return client.fetch(
2269
2284
  `/me/companies/${encodeURIComponent(slug)}/custom-fields`,
@@ -2277,6 +2292,26 @@ function meNamespace(client) {
2277
2292
  { ...options, method: "PATCH", body }
2278
2293
  );
2279
2294
  },
2295
+ /**
2296
+ * Upload one file to an owner-editable `image_gallery` or `file` field
2297
+ * of a company I belong to (up to 10 MB; galleries take JPEG, PNG, WebP
2298
+ * or GIF). The file is a draft until its `id` is saved to the field with
2299
+ * `updateCustomFields`, as the ordered list of file IDs.
2300
+ *
2301
+ * @example
2302
+ * const image = await board.me.companies.uploadCustomFieldFile('acme', 'office_photos', file);
2303
+ * await board.me.companies.updateCustomFields('acme', {
2304
+ * values: { office_photos: [...savedIds, image.id] },
2305
+ * });
2306
+ */
2307
+ uploadCustomFieldFile(slug, fieldKey, file, options) {
2308
+ const form = new FormData();
2309
+ form.append("file", file);
2310
+ return client.fetch(
2311
+ `/me/companies/${encodeURIComponent(slug)}/custom-fields/${encodeURIComponent(fieldKey)}/files`,
2312
+ { ...options, method: "POST", body: form }
2313
+ );
2314
+ },
2280
2315
  /**
2281
2316
  * Delete a company I admin (soft-delete cascade + Forager
2282
2317
  * exclusion). Resolves void on success (204).
@@ -4803,6 +4838,29 @@ function createBoardClient(options) {
4803
4838
  seo(options2) {
4804
4839
  return client.fetch("/seo", options2);
4805
4840
  },
4841
+ /**
4842
+ * Sign an address up for the board's email from a newsletter form. Sends
4843
+ * a confirmation email; nothing is granted until the person clicks it.
4844
+ * Always resolves `{ status: 'submitted', sendingPaused }`. Limited to 3
4845
+ * a minute per address and 10 requests a minute per IP; on a builder
4846
+ * site Cavuno hosts the IP limit counts each visitor, plus 6 sign-ups a
4847
+ * minute per visitor (429 `rate_limited`).
4848
+ *
4849
+ * @example
4850
+ * await board.subscribe({
4851
+ * email,
4852
+ * consent: true,
4853
+ * consentText: 'Send me news and offers from Acme Jobs.',
4854
+ * source: 'blog-footer',
4855
+ * });
4856
+ */
4857
+ subscribe(input, options2) {
4858
+ return client.fetch("/subscribe", {
4859
+ ...options2,
4860
+ method: "POST",
4861
+ body: input
4862
+ });
4863
+ },
4806
4864
  jobs: jobsNamespace(client),
4807
4865
  embed: embedNamespace(client),
4808
4866
  companies: companiesNamespace(client),
package/dist/index.mjs CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  isSsoRequired,
29
29
  isUnauthorized,
30
30
  isValidationError
31
- } from "./chunk-7SAHE7UW.mjs";
31
+ } from "./chunk-AQD4OMX4.mjs";
32
32
 
33
33
  // src/query.ts
34
34
  function toSearchParams(query) {
@@ -49,7 +49,7 @@ function toSearchParams(query) {
49
49
  }
50
50
 
51
51
  // src/version.ts
52
- var SDK_VERSION = "4.69.0";
52
+ var SDK_VERSION = "4.71.0";
53
53
 
54
54
  // src/client.ts
55
55
  function isRawBody(body) {
@@ -1010,13 +1010,21 @@ function jobAlertsNamespace(client) {
1010
1010
  body: input
1011
1011
  });
1012
1012
  },
1013
- /** Re-activate a previously unsubscribed subscription via the manage token. */
1013
+ /**
1014
+ * Resume a previously unsubscribed subscription via the manage token.
1015
+ * `status` is `resubscribed`, or `confirmation_sent` when the address
1016
+ * never confirmed: a confirmation email went out and the alerts start
1017
+ * once it is clicked.
1018
+ */
1014
1019
  resubscribe(input, options) {
1015
- return client.fetch("/job-alerts/resubscribe", {
1016
- ...options,
1017
- method: "POST",
1018
- body: input
1019
- });
1020
+ return client.fetch(
1021
+ "/job-alerts/resubscribe",
1022
+ {
1023
+ ...options,
1024
+ method: "POST",
1025
+ body: input
1026
+ }
1027
+ );
1020
1028
  },
1021
1029
  /** Edit a preference's filters/frequency via the manage token. */
1022
1030
  updatePreference(input, options) {
@@ -1862,7 +1870,10 @@ function meNamespace(client) {
1862
1870
  { ...options, method: "PATCH", body }
1863
1871
  );
1864
1872
  },
1865
- /** Retrieve profile custom fields for a company I belong to. */
1873
+ /**
1874
+ * Retrieve profile custom fields for a company I belong to, with the
1875
+ * saved files of upload fields (`customFieldMedia`).
1876
+ */
1866
1877
  retrieveCustomFields(slug, options) {
1867
1878
  return client.fetch(
1868
1879
  `/me/companies/${encodeURIComponent(slug)}/custom-fields`,
@@ -1876,6 +1887,26 @@ function meNamespace(client) {
1876
1887
  { ...options, method: "PATCH", body }
1877
1888
  );
1878
1889
  },
1890
+ /**
1891
+ * Upload one file to an owner-editable `image_gallery` or `file` field
1892
+ * of a company I belong to (up to 10 MB; galleries take JPEG, PNG, WebP
1893
+ * or GIF). The file is a draft until its `id` is saved to the field with
1894
+ * `updateCustomFields`, as the ordered list of file IDs.
1895
+ *
1896
+ * @example
1897
+ * const image = await board.me.companies.uploadCustomFieldFile('acme', 'office_photos', file);
1898
+ * await board.me.companies.updateCustomFields('acme', {
1899
+ * values: { office_photos: [...savedIds, image.id] },
1900
+ * });
1901
+ */
1902
+ uploadCustomFieldFile(slug, fieldKey, file, options) {
1903
+ const form = new FormData();
1904
+ form.append("file", file);
1905
+ return client.fetch(
1906
+ `/me/companies/${encodeURIComponent(slug)}/custom-fields/${encodeURIComponent(fieldKey)}/files`,
1907
+ { ...options, method: "POST", body: form }
1908
+ );
1909
+ },
1879
1910
  /**
1880
1911
  * Delete a company I admin (soft-delete cascade + Forager
1881
1912
  * exclusion). Resolves void on success (204).
@@ -4372,6 +4403,29 @@ function createBoardClient(options) {
4372
4403
  seo(options2) {
4373
4404
  return client.fetch("/seo", options2);
4374
4405
  },
4406
+ /**
4407
+ * Sign an address up for the board's email from a newsletter form. Sends
4408
+ * a confirmation email; nothing is granted until the person clicks it.
4409
+ * Always resolves `{ status: 'submitted', sendingPaused }`. Limited to 3
4410
+ * a minute per address and 10 requests a minute per IP; on a builder
4411
+ * site Cavuno hosts the IP limit counts each visitor, plus 6 sign-ups a
4412
+ * minute per visitor (429 `rate_limited`).
4413
+ *
4414
+ * @example
4415
+ * await board.subscribe({
4416
+ * email,
4417
+ * consent: true,
4418
+ * consentText: 'Send me news and offers from Acme Jobs.',
4419
+ * source: 'blog-footer',
4420
+ * });
4421
+ */
4422
+ subscribe(input, options2) {
4423
+ return client.fetch("/subscribe", {
4424
+ ...options2,
4425
+ method: "POST",
4426
+ body: input
4427
+ });
4428
+ },
4375
4429
  jobs: jobsNamespace(client),
4376
4430
  embed: embedNamespace(client),
4377
4431
  companies: companiesNamespace(client),
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.js';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.js';
2
2
 
3
3
  /**
4
4
  * Optional pagination metadata returned by Board API list operations.
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.mjs';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.mjs';
2
2
 
3
3
  /**
4
4
  * Optional pagination metadata returned by Board API list operations.
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.mjs';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.mjs';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.js';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.js';
2
2
 
3
3
  type Awaitable<T> = T | Promise<T>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.js';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.js';
2
2
 
3
3
  /**
4
4
  * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-CFOj7Qdf.mjs';
1
+ import { S as Schemas } from './_spec-OPrym0QJ.mjs';
2
2
 
3
3
  /**
4
4
  * The public SEO-infra payload (`board.seo()`) — platform infrastructure a
@@ -1,5 +1,5 @@
1
- import { B as BoardSeo } from './seo-FKj1pSHZ.mjs';
2
- import './_spec-CFOj7Qdf.mjs';
1
+ import { B as BoardSeo } from './seo-DGdqWPLo.mjs';
2
+ import './_spec-OPrym0QJ.mjs';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
@@ -1,5 +1,5 @@
1
- import { B as BoardSeo } from './seo-CGy4fY5a.js';
2
- import './_spec-CFOj7Qdf.js';
1
+ import { B as BoardSeo } from './seo-CW1JjEXH.js';
2
+ import './_spec-OPrym0QJ.js';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/seo-files` — platform-owned crawler/identity file bodies
package/dist/seo-files.js CHANGED
@@ -50,6 +50,7 @@ function listingRoot(value, fallback) {
50
50
  return safeListingRoot(value) ?? fallback;
51
51
  }
52
52
  var LISTING_GROUPS = ["jobs", "companies", "talent"];
53
+ var CONTENT_SIGNAL = "Content-Signal: search=yes, ai-input=yes, ai-train=yes";
53
54
  function paginationRules(root) {
54
55
  return [
55
56
  `Disallow: ${root}?page=`,
@@ -78,6 +79,11 @@ function robotsBody(input) {
78
79
  }
79
80
  return [
80
81
  "User-Agent: *",
82
+ // Content Signals (contentsignals.org): how crawlers may use the board's
83
+ // content once fetched. Boards opt in to every use. The line sits inside
84
+ // the `User-Agent: *` group so it applies to all agents. The sandbox body
85
+ // above leaves it out because it allows no crawling at all.
86
+ CONTENT_SIGNAL,
81
87
  "Allow: /",
82
88
  "Disallow: /go/",
83
89
  "Disallow: /t/",
@@ -18,6 +18,7 @@ function listingRoot(value, fallback) {
18
18
  return safeListingRoot(value) ?? fallback;
19
19
  }
20
20
  var LISTING_GROUPS = ["jobs", "companies", "talent"];
21
+ var CONTENT_SIGNAL = "Content-Signal: search=yes, ai-input=yes, ai-train=yes";
21
22
  function paginationRules(root) {
22
23
  return [
23
24
  `Disallow: ${root}?page=`,
@@ -46,6 +47,11 @@ function robotsBody(input) {
46
47
  }
47
48
  return [
48
49
  "User-Agent: *",
50
+ // Content Signals (contentsignals.org): how crawlers may use the board's
51
+ // content once fetched. Boards opt in to every use. The line sits inside
52
+ // the `User-Agent: *` group so it applies to all agents. The sandbox body
53
+ // above leaves it out because it allows no crawling at all.
54
+ CONTENT_SIGNAL,
49
55
  "Allow: /",
50
56
  "Disallow: /go/",
51
57
  "Disallow: /t/",
package/dist/seo.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-DCRBPnpZ.mjs';
2
- import { e as JsonLdObject } from './breadcrumbs-Dwf0yq7B.mjs';
3
- export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-Dwf0yq7B.mjs';
4
- import './_spec-CFOj7Qdf.mjs';
5
- import './board-DMS3I3sJ.mjs';
6
- import './jobs-Cew_q69W.mjs';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-CHQYIhHH.mjs';
2
+ import { e as JsonLdObject } from './breadcrumbs-CSm6P79s.mjs';
3
+ export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-CSm6P79s.mjs';
4
+ import './_spec-OPrym0QJ.mjs';
5
+ import './board-Btc1dzQB.mjs';
6
+ import './jobs-xjE0IrNu.mjs';
7
7
 
8
8
  /**
9
9
  * Blog structured data on the `@cavuno/board` wire types, transcribed from
package/dist/seo.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-BaVJi3q1.js';
2
- import { e as JsonLdObject } from './breadcrumbs-yGijUUtR.js';
3
- export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-yGijUUtR.js';
4
- import './_spec-CFOj7Qdf.js';
5
- import './board-zLt7j6hj.js';
6
- import './jobs-Dz_w1jZq.js';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed } from './blog-BlRb84MY.js';
2
+ import { e as JsonLdObject } from './breadcrumbs-Bv76gXvF.js';
3
+ export { A as ALL_COUNTRY_CODES, B as BreadcrumbItemInput, g as FaqItem, J as JobBreadcrumb, h as JsonLdBoard, N as NumberNotation, i as SENIORITY_ORDER, j as SalaryFaqEntry, k as SalaryJsonLdOptions, l as SalaryOccupationListOptions, b as buildJobBreadcrumbs, m as buildSalaryFaq, o as companyCategorySalaryJsonLd, p as companySalaryJsonLd, q as createBreadcrumbJsonLd, r as createJobPostingJsonLd, s as crossAxisSalaryJsonLd, t as faqJsonLd, c as formatSalaryStat, d as formatSalaryStatRange, u as itemListJsonLd, v as locationSalaryJsonLd, n as normalizeWebsiteUrl, w as skillSalaryJsonLd, x as sortBySeniority, y as titleSalaryJsonLd } from './breadcrumbs-Bv76gXvF.js';
4
+ import './_spec-OPrym0QJ.js';
5
+ import './board-D74R4Iml.js';
6
+ import './jobs-BMG0vrVI.js';
7
7
 
8
8
  /**
9
9
  * Blog structured data on the `@cavuno/board` wire types, transcribed from
package/dist/server.d.mts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-CFOj7Qdf.mjs';
3
- import './search-DwvgvtEg.mjs';
4
- import './jobs-Cew_q69W.mjs';
5
- import './board-DMS3I3sJ.mjs';
6
- import './seo-FKj1pSHZ.mjs';
7
- import './blog-DCRBPnpZ.mjs';
2
+ import './_spec-OPrym0QJ.mjs';
3
+ import './search-BJkiU3Ic.mjs';
4
+ import './jobs-xjE0IrNu.mjs';
5
+ import './board-Btc1dzQB.mjs';
6
+ import './seo-DGdqWPLo.mjs';
7
+ import './blog-CHQYIhHH.mjs';
8
8
 
9
9
  /**
10
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './_spec-CFOj7Qdf.js';
3
- import './search-BqAYR47P.js';
4
- import './jobs-Dz_w1jZq.js';
5
- import './board-zLt7j6hj.js';
6
- import './seo-CGy4fY5a.js';
7
- import './blog-BaVJi3q1.js';
2
+ import './_spec-OPrym0QJ.js';
3
+ import './search-suUh-E7O.js';
4
+ import './jobs-BMG0vrVI.js';
5
+ import './board-D74R4Iml.js';
6
+ import './seo-CW1JjEXH.js';
7
+ import './blog-BlRb84MY.js';
8
8
 
9
9
  /**
10
10
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-Z4ALWIGS.mjs";
5
5
  import {
6
6
  isUnauthorized
7
- } from "./chunk-7SAHE7UW.mjs";
7
+ } from "./chunk-AQD4OMX4.mjs";
8
8
 
9
9
  // src/server/cookie.ts
10
10
  var COOKIE_ATTRIBUTES = "Path=/; HttpOnly; Secure; SameSite=Lax";
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './_spec-CFOj7Qdf.mjs';
3
- import './search-DwvgvtEg.mjs';
4
- import './jobs-Cew_q69W.mjs';
5
- import './board-DMS3I3sJ.mjs';
6
- import './seo-FKj1pSHZ.mjs';
7
- import './blog-DCRBPnpZ.mjs';
2
+ import './_spec-OPrym0QJ.mjs';
3
+ import './search-BJkiU3Ic.mjs';
4
+ import './jobs-xjE0IrNu.mjs';
5
+ import './board-Btc1dzQB.mjs';
6
+ import './seo-DGdqWPLo.mjs';
7
+ import './blog-CHQYIhHH.mjs';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './_spec-CFOj7Qdf.js';
3
- import './search-BqAYR47P.js';
4
- import './jobs-Dz_w1jZq.js';
5
- import './board-zLt7j6hj.js';
6
- import './seo-CGy4fY5a.js';
7
- import './blog-BaVJi3q1.js';
2
+ import './_spec-OPrym0QJ.js';
3
+ import './search-suUh-E7O.js';
4
+ import './jobs-BMG0vrVI.js';
5
+ import './board-D74R4Iml.js';
6
+ import './seo-CW1JjEXH.js';
7
+ import './blog-BlRb84MY.js';
8
8
 
9
9
  /**
10
10
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-DLSO6XXY.mjs";
4
4
  import {
5
5
  isNotFound
6
- } from "./chunk-7SAHE7UW.mjs";
6
+ } from "./chunk-AQD4OMX4.mjs";
7
7
  import {
8
8
  BOARD_PATHS,
9
9
  blogAuthorPath,
@@ -1,5 +1,5 @@
1
- import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-DwvgvtEg.mjs';
2
- import './_spec-CFOj7Qdf.mjs';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-BJkiU3Ic.mjs';
2
+ import './_spec-OPrym0QJ.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 { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-BqAYR47P.js';
2
- import './_spec-CFOj7Qdf.js';
1
+ import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-suUh-E7O.js';
2
+ import './_spec-OPrym0QJ.js';
3
3
 
4
4
  /**
5
5
  * `@cavuno/board/suggest` — framework-agnostic headless search-suggest
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "4.69.0",
3
+ "version": "4.71.0",
4
4
  "description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -217,6 +217,22 @@ await board.me.profile.updateCustomFields({
217
217
  });
218
218
  ```
219
219
 
220
+ Company members upload to the company's upload fields the same way, with the company slug first. `customFieldMedia` on `board.me.companies.retrieveCustomFields` lists the saved files.
221
+
222
+ ```ts snippet
223
+ const company = await board.me.companies.retrieveCustomFields('acme');
224
+ const photos = Array.isArray(company.values.office_photos)
225
+ ? company.values.office_photos
226
+ : [];
227
+ const photo = await board.me.companies.uploadCustomFieldFile(
228
+ 'acme',
229
+ 'office_photos',
230
+ file);
231
+ await board.me.companies.updateCustomFields('acme', {
232
+ values: { office_photos: [...photos, photo.id] },
233
+ });
234
+ ```
235
+
220
236
  Resume upload starts an asynchronous parse that may populate the profile. Poll within a fixed budget, surface failure, and keep manual editing available if parsing runs long.
221
237
 
222
238
  ```ts snippet
@@ -28,6 +28,7 @@ await board.auth.register({
28
28
  email: 'ada@example.com',
29
29
  password: 'a-strong-password',
30
30
  displayName: 'Ada',
31
+ timeZone: browserTimeZone, // read in the browser, sent with the form
31
32
  });
32
33
 
33
34
  const session = await board.auth.login({
@@ -40,6 +41,8 @@ const session = await board.auth.login({
40
41
 
41
42
  For alternate entry points, use `requestMagicLink` / `consumeMagicLink` or the OAuth authorization and exchange methods exposed under `board.auth`.
42
43
 
44
+ Pass `timeZone` to `register` and `consumeMagicLink`: the person's IANA time zone from `Intl.DateTimeFormat().resolvedOptions().timeZone`, read in their browser (such as `Europe/Berlin`). On your server it returns the server's zone, so never fill it in there. The board keeps the first value it gets for a person and ignores an invalid one, so it never fails the sign-up.
45
+
43
46
  **Complete when:** the chosen entry flow returns a session and `board.me.retrieve()` resolves as that board user.
44
47
 
45
48
  ## 3. Handle expiry explicitly
@@ -16,6 +16,8 @@ Both lanes are available only when `board.context()` reports `features.jobAlerts
16
16
 
17
17
  `subscribe` requires consent and deliberately returns the same submitted response for new and existing addresses. `confirm` always resolves; its status owns the landing-page branch.
18
18
 
19
+ Send the person's time zone as `timeZone`: read `Intl.DateTimeFormat().resolvedOptions().timeZone` in their browser (such as `Europe/Berlin`) and pass it with the form. On your server it returns the server's zone, so never fill it in there. The board keeps the first value it gets for a person and ignores an invalid one.
20
+
19
21
  ```ts snippet
20
22
  const submitted = await board.jobAlerts.subscribe({
21
23
  email: 'ada@example.com',
@@ -26,20 +28,28 @@ const submitted = await board.jobAlerts.subscribe({
26
28
  remoteOptions: ['remote'],
27
29
  placeSlugs: ['berlin'],
28
30
  },
31
+ timeZone: browserTimeZone, // read in the browser, sent with the form
29
32
  });
30
33
 
31
34
  const result = await board.jobAlerts.confirm({ token });
32
35
  switch (result.status) {
33
36
  case 'confirmed':
34
37
  case 'already_confirmed':
38
+ case 'waitlisted':
35
39
  case 'not_found':
36
40
  break;
41
+ case 'unsubscribed':
42
+ // Offer the subscribe form again (it emails a fresh confirmation link)
43
+ // or the manage page's resume option.
44
+ break;
37
45
  case 'expired':
38
46
  await board.jobAlerts.resendConfirmation({ email });
39
47
  break;
40
48
  }
41
49
  ```
42
50
 
51
+ `waitlisted` means the alert is confirmed but the board can't send to more people yet; it starts once a spot opens. `unsubscribed` means the link was sent before the alerts were turned off, so it doesn't turn them back on. Subscribing again with the form sends that address a fresh confirmation email, at most once every 12 hours and never while it is suppressed or when the board's team unsubscribed the address; clicking it resumes the alerts. The manage link in an alert email (`board.jobAlerts.resubscribe`) and signing in to create an alert resume them too.
52
+
43
53
  Only `jobFunctions`, `placeSlugs`, and `remoteOptions` filter digest delivery. Seniority and salary fields are stored but do not scope delivery. The supported cadence is `weekly`.
44
54
 
45
55
  `jobFunctions` are category and skill slugs (the `slug` of a category or skill, such as `engineering` or `media-and-communication`). A digest matches a job when any entry equals one of the job's category or skill slugs. Prefer sending slugs. If you send display names or free-text keywords instead, the server slugifies each one when the alert is saved and matches it against the board's category and skill slugs, their aliases, and their board-language slugs. A display name that does not slugify to one of those (for example, a renamed category) is stored slugified and will not match, so send slugs whenever you have them. Alerts read back from the API therefore always carry slugs, so compare and display them as slugs.
@@ -95,6 +105,8 @@ await board.jobAlerts.deletePreference({
95
105
 
96
106
  `unsubscribe` and `resubscribe` accept an optional `preferenceId`. Each managed preference also includes its own `manageToken`.
97
107
 
108
+ `resubscribe` returns `status`: `resubscribed` means the subscription is resumed. `confirmation_sent` means the address never confirmed, so a confirmation email went out instead; keep showing the alerts as off and tell the person to check their inbox. A 429 means rate limiting or a confirmation email requested in the last two minutes; nothing new was sent. A 409 (`job_alert_email_suppressed`) means the address never confirmed and can't receive email, so nothing was sent; keep the alerts off and don't retry. A 502 (`job_alert_confirmation_send_failed`) means the email could not be sent.
109
+
98
110
  `updatePreference` is a full replacement. Round-trip every retained value and always send `frequency`.
99
111
 
100
112
  ```ts snippet