@cavuno/board 4.34.0 → 4.36.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 (41) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/{_spec-Cz-yijWv.d.mts → _spec-C4T68Nnr.d.mts} +56 -8
  3. package/dist/{_spec-Cz-yijWv.d.ts → _spec-C4T68Nnr.d.ts} +56 -8
  4. package/dist/bin.mjs +32 -22
  5. package/dist/{blog-BtZXryRt.d.ts → blog-_LtV-JaY.d.ts} +1 -1
  6. package/dist/{blog-CA6EEkdC.d.mts → blog-bQmqKnw2.d.mts} +1 -1
  7. package/dist/{board-BKUGfCIT.d.mts → board-2UfZ7fZk.d.ts} +11 -3
  8. package/dist/{board-Dlv-nGl3.d.ts → board-CRgQjnrn.d.mts} +11 -3
  9. package/dist/{breadcrumbs-D9p_vb0h.d.ts → breadcrumbs-C_jNh4xd.d.ts} +2 -2
  10. package/dist/{breadcrumbs-w0szfoX0.d.mts → breadcrumbs-f7KFSWnx.d.mts} +2 -2
  11. package/dist/browser/cavuno-board.global.min.js +1 -1
  12. package/dist/doctor.d.mts +41 -1
  13. package/dist/doctor.d.ts +41 -1
  14. package/dist/doctor.js +59 -22
  15. package/dist/doctor.mjs +58 -22
  16. package/dist/filters.d.mts +2 -2
  17. package/dist/filters.d.ts +2 -2
  18. package/dist/format.d.mts +4 -4
  19. package/dist/format.d.ts +4 -4
  20. package/dist/index.d.mts +56 -12
  21. package/dist/index.d.ts +56 -12
  22. package/dist/index.js +4 -2
  23. package/dist/index.mjs +4 -2
  24. package/dist/{jobs-D0OqM6IS.d.ts → jobs-3Md7CCMl.d.ts} +13 -2
  25. package/dist/{jobs-DCeOWaPk.d.mts → jobs-Cg2d2oI4.d.mts} +13 -2
  26. package/dist/{search-pH_zLJ23.d.ts → search-15gcqPyt.d.ts} +1 -1
  27. package/dist/{search-DCRz5E-6.d.mts → search-CyDzceiR.d.mts} +1 -1
  28. package/dist/{seo-CO1235tn.d.ts → seo-CON8CLIF.d.ts} +1 -1
  29. package/dist/{seo-CRJDxQMf.d.mts → seo-DuWLAh1M.d.mts} +1 -1
  30. package/dist/seo-files.d.mts +2 -2
  31. package/dist/seo-files.d.ts +2 -2
  32. package/dist/seo.d.mts +6 -6
  33. package/dist/seo.d.ts +6 -6
  34. package/dist/server.d.mts +6 -6
  35. package/dist/server.d.ts +6 -6
  36. package/dist/sitemap.d.mts +6 -6
  37. package/dist/sitemap.d.ts +6 -6
  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/manifest.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,53 @@
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.36.0 — 2026-10-06
7
+
8
+ - `board.get()` returns `ads.googleConsentMessage`. It is `true` when visitors
9
+ in the EEA, UK and Switzerland should get Google's certified consent message
10
+ (published in AdSense Privacy & messaging) instead of the board's own cookie
11
+ banner: AdSense is on with a valid `clientId` and the owner has not turned
12
+ the setting off. Load the AdSense tag on page load when it is `true`, and
13
+ gate other trackers on the visitor's answer to Google's message.
14
+
15
+ - Creating a job whose `applicationUrl` is already used by another job on the
16
+ account still returns `409 jobs_already_exists`, now with
17
+ `details.matched_on` and, for `application_url` matches,
18
+ `details.matching_jobs` (up to 5 `{ id, title, status }`). If the new job is
19
+ a different role that shares that application destination, retry with the
20
+ new optional `allowSharedApplicationUrl: true`. A matching `externalId` or an
21
+ identical job still cannot be overridden. Always set `externalId`.
22
+
23
+ - Place names on job surfaces now follow the board language: card
24
+ `locationLabel` (jobs list, search, similar, company jobs, saved jobs),
25
+ job detail `officeLocations[].displayName` and `placeHierarchy[].name`.
26
+ Hierarchy slugs are unchanged.
27
+
28
+ ## 4.35.0 — 2026-10-05
29
+
30
+ - Boards can define custom employment types, such as "Casual", each with a
31
+ built-in type as its Google equivalent. Jobs gain
32
+ `customEmploymentType: { key, label } | null`; `employmentType` still holds
33
+ the built-in type, which is what Google for Jobs markup and job feeds use.
34
+ Show `customEmploymentType.label` when it is set.
35
+
36
+ - The board context lists a board's custom types under
37
+ `jobForm.employmentType.customTypes` (`key`, `label`, `employmentType`,
38
+ `offered`) and the full display order under `jobForm.employmentType.order`.
39
+ `allowedOptions` and `customTypes` are returned in that order. Types that
40
+ are not offered stay listed so existing jobs keep their label.
41
+
42
+ - Job search and listing accept a `customEmploymentType` filter (keys). A
43
+ built-in `employmentType` filter value now matches jobs of that type that
44
+ have no custom type, so "Part-time" does not return "Casual" jobs.
45
+
46
+ - Job posting and employer job writes accept `customEmploymentType` (a key);
47
+ the matching built-in type is set automatically.
48
+
49
+ - Links to non-image files in public company custom fields are signed and
50
+ expire after at least 24 hours, so they work on password-protected boards.
51
+ Request fresh company data rather than storing these links.
52
+
6
53
  ## 4.34.0 — 2026-10-05
7
54
 
8
55
  - Added `analytics.recordConsent` to record a visitor's cookie-banner choice
@@ -319,6 +319,16 @@ interface components {
319
319
  enabled: boolean;
320
320
  boardName: string;
321
321
  };
322
+ BoardCustomEmploymentType: {
323
+ /** @description Stable key. Send it as `customEmploymentType` when posting a job, and filter jobs by it. */
324
+ key: string;
325
+ /** @description Display name, e.g. `Casual`. */
326
+ label: string;
327
+ /** @description The custom type's Google equivalent: a built-in employment type. Send it as `employmentType` alongside the key; it is what Google for Jobs and job feeds see. */
328
+ employmentType: string;
329
+ /** @description Whether posters can pick this type. An un-offered type still labels the jobs that already use it; leave it out of a posting form. */
330
+ offered: boolean;
331
+ };
322
332
  BoardFormBuiltinField: {
323
333
  /**
324
334
  * @description discriminator enum property added by openapi-typescript
@@ -948,6 +958,8 @@ interface components {
948
958
  title: string;
949
959
  description: string;
950
960
  employmentType: string;
961
+ /** @description Key of one of the board's custom employment types (board context `jobForm.employmentType.customTypes`). `employmentType` must be the Google equivalent of that type; an unknown key, a type with `offered: false`, or a different `employmentType` returns `400`. */
962
+ customEmploymentType?: string;
951
963
  remoteOption: string;
952
964
  officeLocations: {
953
965
  /**
@@ -1244,10 +1256,12 @@ interface components {
1244
1256
  /** @description URL-friendly slug for the job. Auto-generated from `title` when omitted. */
1245
1257
  slug?: string;
1246
1258
  /**
1247
- * @description Employment type of the role.
1259
+ * @description Employment type of the role. When `customEmploymentType` is also sent, this must be the Google equivalent of that custom type (or be omitted: the server sets it). Sending a built-in type without `customEmploymentType` clears any custom type on the job.
1248
1260
  * @enum {string}
1249
1261
  */
1250
1262
  employmentType?: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other";
1263
+ /** @description Key of one of the board's custom employment types (`GET /v1/settings/job-form` → `employmentType.customTypes`). The job is saved with the Google equivalent of that type as its built-in `employmentType`, which is what Google for Jobs and feeds see. An unknown key, a type the board no longer offers (`offered: false`), or an `employmentType` that differs from its Google equivalent returns `400 jobs_constraint_violation`. Pass `null` to clear the custom type and keep the built-in; omitted means unchanged. */
1264
+ customEmploymentType?: string | null;
1251
1265
  /**
1252
1266
  * @description **Required.** Whether the role is on-site, hybrid, or fully remote: one of `on_site`, `hybrid`, `remote`. Omitting it or sending `null` returns `400`. It is not valid on its own either: `on_site` and `hybrid` require at least one `officeLocations` entry, and `remote` requires `remotePermits` (use `[{"type":"worldwide","value":"worldwide"}]` for anywhere; `remoteTimezones` then auto-derives on POST).
1253
1267
  * @enum {string}
@@ -1436,10 +1450,17 @@ interface components {
1436
1450
  /** @description Identifier of the company the job belongs to, or `null` if no company is attached. */
1437
1451
  companyId: string | null;
1438
1452
  /**
1439
- * @description Employment type of the role, or `null` if not specified.
1453
+ * @description Employment type of the role, or `null` if not specified. For a job with a custom employment type, this is the Google equivalent of the custom type.
1440
1454
  * @enum {string|null}
1441
1455
  */
1442
1456
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
1457
+ /** @description The board's custom employment type for this job (for example `Casual`), or `null` when the job uses a built-in type only. A deleted custom type reads back as `null` and the job shows its built-in `employmentType`. */
1458
+ customEmploymentType: {
1459
+ /** @description Stable key of the custom employment type. Never changes. */
1460
+ key: string;
1461
+ /** @description Display name of the custom employment type, as configured. */
1462
+ label: string;
1463
+ } | null;
1443
1464
  /**
1444
1465
  * @description Whether the role is on-site, hybrid, or fully remote. `null` only on older jobs saved without one; create requires it and `PATCH` cannot clear it.
1445
1466
  * @enum {string|null}
@@ -1539,10 +1560,12 @@ interface components {
1539
1560
  /** @description URL-friendly slug for the job. Auto-generated from `title` when omitted. */
1540
1561
  slug?: string;
1541
1562
  /**
1542
- * @description Employment type of the role.
1563
+ * @description Employment type of the role. When `customEmploymentType` is also sent, this must be the Google equivalent of that custom type (or be omitted: the server sets it). Sending a built-in type without `customEmploymentType` clears any custom type on the job.
1543
1564
  * @enum {string}
1544
1565
  */
1545
1566
  employmentType?: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other";
1567
+ /** @description Key of one of the board's custom employment types (`GET /v1/settings/job-form` → `employmentType.customTypes`). The job is saved with the Google equivalent of that type as its built-in `employmentType`, which is what Google for Jobs and feeds see. An unknown key, a type the board no longer offers (`offered: false`), or an `employmentType` that differs from its Google equivalent returns `400 jobs_constraint_violation`. Pass `null` to clear the custom type and keep the built-in; omitted means unchanged. */
1568
+ customEmploymentType?: string | null;
1546
1569
  /**
1547
1570
  * @description Whether the role is on-site, hybrid, or fully remote. Omitted means unchanged; `null` returns `400` because a job's workplace type can be changed but not cleared. **Never valid on its own:** `on_site` and `hybrid` require at least one `officeLocations` entry, and `remote` requires `remotePermits` (use `[{"type":"worldwide","value":"worldwide"}]` for anywhere; `remoteTimezones` then auto-derives on POST). Sending it alone returns `400`.
1548
1571
  * @enum {string}
@@ -2356,6 +2379,8 @@ interface components {
2356
2379
  clientId: string | null;
2357
2380
  /** @description Default Google-issued ad unit id (10 digits). Resolves the enabled jobs:list.footer slot first, then the first enabled valid slot in alphabetical placement-key order. Null when advertising is off, the publisher id is invalid, or no enabled valid slot exists. Frontends may override it per ad unit. */
2358
2381
  defaultSlotId: string | null;
2382
+ /** @description True when visitors in the EEA, UK and Switzerland should get Google's certified consent message (published by the owner in AdSense → Privacy & messaging) instead of the board's own cookie banner. On by default whenever AdSense is on with a valid `clientId`; false when the owner turns it off, ads are off, or the publisher id is invalid. When true, load the AdSense tag on page load so Google's consent message can appear, and gate other trackers on the visitor's answer to it. */
2383
+ googleConsentMessage: boolean;
2359
2384
  };
2360
2385
  /** @description Operator-defined custom field definitions keyed by model (currently only `job`). Each key holds that model's definitions in display order. The frontend uses these to render and localize each record's opaque `customFieldValues`. Supports exact-value custom-field filters in job search. Profile definitions are discovered through the profile-fields endpoint. */
2361
2386
  customFields: {
@@ -2401,8 +2426,12 @@ interface components {
2401
2426
  allowedOptions: string[];
2402
2427
  };
2403
2428
  employmentType: {
2404
- /** @description Employment types the board accepts, fully resolved like `seniority.allowedOptions`. A single entry means the form must collapse the field. */
2429
+ /** @description Built-in employment types the board accepts, fully resolved like `seniority.allowedOptions` and sorted by `order`. Empty when the board offers only custom types (`customTypes`). When the built-ins and offered custom types together come to a single option, the form must collapse the field. */
2405
2430
  allowedOptions: string[];
2431
+ /** @description The board's custom employment types, sorted by `order`, offered or not. Offer the `offered` ones next to `allowedOptions` in a posting form's employment type picker; use all of them to label jobs. Always an array (empty when the board defines none). */
2432
+ customTypes: components["schemas"]["BoardCustomEmploymentType"][];
2433
+ /** @description The board's employment type display order: every built-in value and every custom type key, each once. Sort a posting form's employment type picker by it. */
2434
+ order: string[];
2406
2435
  };
2407
2436
  };
2408
2437
  forms: components["schemas"]["BoardForms"];
@@ -2484,10 +2513,17 @@ interface components {
2484
2513
  /** @description Identifier of the company the job belongs to, or `null` if no company is attached. */
2485
2514
  companyId: string | null;
2486
2515
  /**
2487
- * @description Employment type of the role, or `null` if not specified.
2516
+ * @description Employment type of the role, or `null` if not specified. For a job with a custom employment type, this is the Google equivalent of the custom type.
2488
2517
  * @enum {string|null}
2489
2518
  */
2490
2519
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
2520
+ /** @description The board's custom employment type for this job (for example `Casual`), or `null` when the job uses a built-in type only. A deleted custom type reads back as `null` and the job shows its built-in `employmentType`. */
2521
+ customEmploymentType: {
2522
+ /** @description Stable key of the custom employment type. Never changes. */
2523
+ key: string;
2524
+ /** @description Display name of the custom employment type, as configured. */
2525
+ label: string;
2526
+ } | null;
2491
2527
  /**
2492
2528
  * @description Whether the role is on-site, hybrid, or fully remote. `null` only on older jobs saved without one; create requires it and `PATCH` cannot clear it.
2493
2529
  * @enum {string|null}
@@ -2577,7 +2613,7 @@ interface components {
2577
2613
  slug: string;
2578
2614
  name: string;
2579
2615
  }[];
2580
- /** @description Place ancestor chain (country → region → city) for the breadcrumb; each `{slug,name}` links to `/jobs/locations/:slug`. Source-language. */
2616
+ /** @description Place ancestor chain (country → region → city) for the breadcrumb; each `{slug,name}` links to `/jobs/locations/:slug`. `name` is in the board's language (the source name where the place has no translation); `slug` is the source slug. */
2581
2617
  placeHierarchy: {
2582
2618
  slug: string;
2583
2619
  name: string;
@@ -2656,8 +2692,18 @@ interface components {
2656
2692
  * @description ISO 8601 publish timestamp, or `null` if unpublished.
2657
2693
  */
2658
2694
  publishedAt: string | null;
2659
- /** @enum {string|null} */
2695
+ /**
2696
+ * @description Built-in employment type. For a job with a custom employment type, the Google equivalent of that type.
2697
+ * @enum {string|null}
2698
+ */
2660
2699
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
2700
+ /** @description The board's custom employment type for this job (show its `label` instead of the built-in), or `null`. */
2701
+ customEmploymentType: {
2702
+ /** @description Stable key of the custom employment type. Never changes. */
2703
+ key: string;
2704
+ /** @description Display name of the custom employment type, as configured. */
2705
+ label: string;
2706
+ } | null;
2661
2707
  /** @enum {string|null} */
2662
2708
  remoteOption: "on_site" | "hybrid" | "remote" | null;
2663
2709
  /** @description Display region label for remote jobs (e.g. "United States", "Worldwide"); `null` for non-remote jobs. */
@@ -2773,8 +2819,10 @@ interface components {
2773
2819
  companySlug?: string[];
2774
2820
  /** @description Only return jobs with any of the given remote-work options. Up to 10 values. */
2775
2821
  remoteOption?: ("on_site" | "hybrid" | "remote")[];
2776
- /** @description Only return jobs with any of the given employment types. Up to 10 values. */
2822
+ /** @description Only return jobs with any of the given built-in employment types. Up to 10 values. A built-in value matches jobs of that type that have no custom employment type: a job with a custom type matches only through `customEmploymentType`. Combined with `customEmploymentType` as a union. */
2777
2823
  employmentType?: ("full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other")[];
2824
+ /** @description Only return jobs with any of the given custom employment type keys (the board's `customTypes`). Up to 10 values. Combined with `employmentType` as a union: a job matches when it has one of these custom types OR one of the given built-in types and no custom type. */
2825
+ customEmploymentType?: string[];
2778
2826
  /** @description Only return jobs at any of the given seniority levels. Up to 10 values. */
2779
2827
  seniority?: ("entry_level" | "associate" | "mid_level" | "senior" | "lead" | "principal" | "director" | "executive")[];
2780
2828
  /** @description Only return jobs tagged with any of the given category slugs. Up to 10 values. Accepts the `sourceSlug` or the board-language `canonicalSlug` from `GET /v1/boards/{identifier}/categories`, or a `slug` from a job card's `categories`. Unknown slugs match no jobs. */
@@ -319,6 +319,16 @@ interface components {
319
319
  enabled: boolean;
320
320
  boardName: string;
321
321
  };
322
+ BoardCustomEmploymentType: {
323
+ /** @description Stable key. Send it as `customEmploymentType` when posting a job, and filter jobs by it. */
324
+ key: string;
325
+ /** @description Display name, e.g. `Casual`. */
326
+ label: string;
327
+ /** @description The custom type's Google equivalent: a built-in employment type. Send it as `employmentType` alongside the key; it is what Google for Jobs and job feeds see. */
328
+ employmentType: string;
329
+ /** @description Whether posters can pick this type. An un-offered type still labels the jobs that already use it; leave it out of a posting form. */
330
+ offered: boolean;
331
+ };
322
332
  BoardFormBuiltinField: {
323
333
  /**
324
334
  * @description discriminator enum property added by openapi-typescript
@@ -948,6 +958,8 @@ interface components {
948
958
  title: string;
949
959
  description: string;
950
960
  employmentType: string;
961
+ /** @description Key of one of the board's custom employment types (board context `jobForm.employmentType.customTypes`). `employmentType` must be the Google equivalent of that type; an unknown key, a type with `offered: false`, or a different `employmentType` returns `400`. */
962
+ customEmploymentType?: string;
951
963
  remoteOption: string;
952
964
  officeLocations: {
953
965
  /**
@@ -1244,10 +1256,12 @@ interface components {
1244
1256
  /** @description URL-friendly slug for the job. Auto-generated from `title` when omitted. */
1245
1257
  slug?: string;
1246
1258
  /**
1247
- * @description Employment type of the role.
1259
+ * @description Employment type of the role. When `customEmploymentType` is also sent, this must be the Google equivalent of that custom type (or be omitted: the server sets it). Sending a built-in type without `customEmploymentType` clears any custom type on the job.
1248
1260
  * @enum {string}
1249
1261
  */
1250
1262
  employmentType?: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other";
1263
+ /** @description Key of one of the board's custom employment types (`GET /v1/settings/job-form` → `employmentType.customTypes`). The job is saved with the Google equivalent of that type as its built-in `employmentType`, which is what Google for Jobs and feeds see. An unknown key, a type the board no longer offers (`offered: false`), or an `employmentType` that differs from its Google equivalent returns `400 jobs_constraint_violation`. Pass `null` to clear the custom type and keep the built-in; omitted means unchanged. */
1264
+ customEmploymentType?: string | null;
1251
1265
  /**
1252
1266
  * @description **Required.** Whether the role is on-site, hybrid, or fully remote: one of `on_site`, `hybrid`, `remote`. Omitting it or sending `null` returns `400`. It is not valid on its own either: `on_site` and `hybrid` require at least one `officeLocations` entry, and `remote` requires `remotePermits` (use `[{"type":"worldwide","value":"worldwide"}]` for anywhere; `remoteTimezones` then auto-derives on POST).
1253
1267
  * @enum {string}
@@ -1436,10 +1450,17 @@ interface components {
1436
1450
  /** @description Identifier of the company the job belongs to, or `null` if no company is attached. */
1437
1451
  companyId: string | null;
1438
1452
  /**
1439
- * @description Employment type of the role, or `null` if not specified.
1453
+ * @description Employment type of the role, or `null` if not specified. For a job with a custom employment type, this is the Google equivalent of the custom type.
1440
1454
  * @enum {string|null}
1441
1455
  */
1442
1456
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
1457
+ /** @description The board's custom employment type for this job (for example `Casual`), or `null` when the job uses a built-in type only. A deleted custom type reads back as `null` and the job shows its built-in `employmentType`. */
1458
+ customEmploymentType: {
1459
+ /** @description Stable key of the custom employment type. Never changes. */
1460
+ key: string;
1461
+ /** @description Display name of the custom employment type, as configured. */
1462
+ label: string;
1463
+ } | null;
1443
1464
  /**
1444
1465
  * @description Whether the role is on-site, hybrid, or fully remote. `null` only on older jobs saved without one; create requires it and `PATCH` cannot clear it.
1445
1466
  * @enum {string|null}
@@ -1539,10 +1560,12 @@ interface components {
1539
1560
  /** @description URL-friendly slug for the job. Auto-generated from `title` when omitted. */
1540
1561
  slug?: string;
1541
1562
  /**
1542
- * @description Employment type of the role.
1563
+ * @description Employment type of the role. When `customEmploymentType` is also sent, this must be the Google equivalent of that custom type (or be omitted: the server sets it). Sending a built-in type without `customEmploymentType` clears any custom type on the job.
1543
1564
  * @enum {string}
1544
1565
  */
1545
1566
  employmentType?: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other";
1567
+ /** @description Key of one of the board's custom employment types (`GET /v1/settings/job-form` → `employmentType.customTypes`). The job is saved with the Google equivalent of that type as its built-in `employmentType`, which is what Google for Jobs and feeds see. An unknown key, a type the board no longer offers (`offered: false`), or an `employmentType` that differs from its Google equivalent returns `400 jobs_constraint_violation`. Pass `null` to clear the custom type and keep the built-in; omitted means unchanged. */
1568
+ customEmploymentType?: string | null;
1546
1569
  /**
1547
1570
  * @description Whether the role is on-site, hybrid, or fully remote. Omitted means unchanged; `null` returns `400` because a job's workplace type can be changed but not cleared. **Never valid on its own:** `on_site` and `hybrid` require at least one `officeLocations` entry, and `remote` requires `remotePermits` (use `[{"type":"worldwide","value":"worldwide"}]` for anywhere; `remoteTimezones` then auto-derives on POST). Sending it alone returns `400`.
1548
1571
  * @enum {string}
@@ -2356,6 +2379,8 @@ interface components {
2356
2379
  clientId: string | null;
2357
2380
  /** @description Default Google-issued ad unit id (10 digits). Resolves the enabled jobs:list.footer slot first, then the first enabled valid slot in alphabetical placement-key order. Null when advertising is off, the publisher id is invalid, or no enabled valid slot exists. Frontends may override it per ad unit. */
2358
2381
  defaultSlotId: string | null;
2382
+ /** @description True when visitors in the EEA, UK and Switzerland should get Google's certified consent message (published by the owner in AdSense → Privacy & messaging) instead of the board's own cookie banner. On by default whenever AdSense is on with a valid `clientId`; false when the owner turns it off, ads are off, or the publisher id is invalid. When true, load the AdSense tag on page load so Google's consent message can appear, and gate other trackers on the visitor's answer to it. */
2383
+ googleConsentMessage: boolean;
2359
2384
  };
2360
2385
  /** @description Operator-defined custom field definitions keyed by model (currently only `job`). Each key holds that model's definitions in display order. The frontend uses these to render and localize each record's opaque `customFieldValues`. Supports exact-value custom-field filters in job search. Profile definitions are discovered through the profile-fields endpoint. */
2361
2386
  customFields: {
@@ -2401,8 +2426,12 @@ interface components {
2401
2426
  allowedOptions: string[];
2402
2427
  };
2403
2428
  employmentType: {
2404
- /** @description Employment types the board accepts, fully resolved like `seniority.allowedOptions`. A single entry means the form must collapse the field. */
2429
+ /** @description Built-in employment types the board accepts, fully resolved like `seniority.allowedOptions` and sorted by `order`. Empty when the board offers only custom types (`customTypes`). When the built-ins and offered custom types together come to a single option, the form must collapse the field. */
2405
2430
  allowedOptions: string[];
2431
+ /** @description The board's custom employment types, sorted by `order`, offered or not. Offer the `offered` ones next to `allowedOptions` in a posting form's employment type picker; use all of them to label jobs. Always an array (empty when the board defines none). */
2432
+ customTypes: components["schemas"]["BoardCustomEmploymentType"][];
2433
+ /** @description The board's employment type display order: every built-in value and every custom type key, each once. Sort a posting form's employment type picker by it. */
2434
+ order: string[];
2406
2435
  };
2407
2436
  };
2408
2437
  forms: components["schemas"]["BoardForms"];
@@ -2484,10 +2513,17 @@ interface components {
2484
2513
  /** @description Identifier of the company the job belongs to, or `null` if no company is attached. */
2485
2514
  companyId: string | null;
2486
2515
  /**
2487
- * @description Employment type of the role, or `null` if not specified.
2516
+ * @description Employment type of the role, or `null` if not specified. For a job with a custom employment type, this is the Google equivalent of the custom type.
2488
2517
  * @enum {string|null}
2489
2518
  */
2490
2519
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
2520
+ /** @description The board's custom employment type for this job (for example `Casual`), or `null` when the job uses a built-in type only. A deleted custom type reads back as `null` and the job shows its built-in `employmentType`. */
2521
+ customEmploymentType: {
2522
+ /** @description Stable key of the custom employment type. Never changes. */
2523
+ key: string;
2524
+ /** @description Display name of the custom employment type, as configured. */
2525
+ label: string;
2526
+ } | null;
2491
2527
  /**
2492
2528
  * @description Whether the role is on-site, hybrid, or fully remote. `null` only on older jobs saved without one; create requires it and `PATCH` cannot clear it.
2493
2529
  * @enum {string|null}
@@ -2577,7 +2613,7 @@ interface components {
2577
2613
  slug: string;
2578
2614
  name: string;
2579
2615
  }[];
2580
- /** @description Place ancestor chain (country → region → city) for the breadcrumb; each `{slug,name}` links to `/jobs/locations/:slug`. Source-language. */
2616
+ /** @description Place ancestor chain (country → region → city) for the breadcrumb; each `{slug,name}` links to `/jobs/locations/:slug`. `name` is in the board's language (the source name where the place has no translation); `slug` is the source slug. */
2581
2617
  placeHierarchy: {
2582
2618
  slug: string;
2583
2619
  name: string;
@@ -2656,8 +2692,18 @@ interface components {
2656
2692
  * @description ISO 8601 publish timestamp, or `null` if unpublished.
2657
2693
  */
2658
2694
  publishedAt: string | null;
2659
- /** @enum {string|null} */
2695
+ /**
2696
+ * @description Built-in employment type. For a job with a custom employment type, the Google equivalent of that type.
2697
+ * @enum {string|null}
2698
+ */
2660
2699
  employmentType: "full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other" | null;
2700
+ /** @description The board's custom employment type for this job (show its `label` instead of the built-in), or `null`. */
2701
+ customEmploymentType: {
2702
+ /** @description Stable key of the custom employment type. Never changes. */
2703
+ key: string;
2704
+ /** @description Display name of the custom employment type, as configured. */
2705
+ label: string;
2706
+ } | null;
2661
2707
  /** @enum {string|null} */
2662
2708
  remoteOption: "on_site" | "hybrid" | "remote" | null;
2663
2709
  /** @description Display region label for remote jobs (e.g. "United States", "Worldwide"); `null` for non-remote jobs. */
@@ -2773,8 +2819,10 @@ interface components {
2773
2819
  companySlug?: string[];
2774
2820
  /** @description Only return jobs with any of the given remote-work options. Up to 10 values. */
2775
2821
  remoteOption?: ("on_site" | "hybrid" | "remote")[];
2776
- /** @description Only return jobs with any of the given employment types. Up to 10 values. */
2822
+ /** @description Only return jobs with any of the given built-in employment types. Up to 10 values. A built-in value matches jobs of that type that have no custom employment type: a job with a custom type matches only through `customEmploymentType`. Combined with `customEmploymentType` as a union. */
2777
2823
  employmentType?: ("full_time" | "part_time" | "contract" | "internship" | "temporary" | "volunteer" | "other")[];
2824
+ /** @description Only return jobs with any of the given custom employment type keys (the board's `customTypes`). Up to 10 values. Combined with `employmentType` as a union: a job matches when it has one of these custom types OR one of the given built-in types and no custom type. */
2825
+ customEmploymentType?: string[];
2778
2826
  /** @description Only return jobs at any of the given seniority levels. Up to 10 values. */
2779
2827
  seniority?: ("entry_level" | "associate" | "mid_level" | "senior" | "lead" | "principal" | "director" | "executive")[];
2780
2828
  /** @description Only return jobs tagged with any of the given category slugs. Up to 10 values. Accepts the `sourceSlug` or the board-language `canonicalSlug` from `GET /v1/boards/{identifier}/categories`, or a `slug` from a job card's `categories`. Unknown slugs match no jobs. */
package/dist/bin.mjs CHANGED
@@ -323,9 +323,8 @@ function truncate(line, max = 120) {
323
323
  const t = line.trim();
324
324
  return t.length > max ? `${t.slice(0, max)}\u2026` : t;
325
325
  }
326
- function checkCookieCodecConformance(projectRoot) {
327
- const srcDir = join2(projectRoot, "src");
328
- if (!existsSync2(srcDir)) {
326
+ function checkCookieSourceText(files, hasSource, unreadable) {
327
+ if (!hasSource) {
329
328
  return [
330
329
  COOKIE(
331
330
  "skip",
@@ -333,33 +332,44 @@ function checkCookieCodecConformance(projectRoot) {
333
332
  )
334
333
  ];
335
334
  }
336
- const files = [];
337
- walkSourceFiles(srcDir, files);
338
335
  const findings = [];
339
- for (const file of files) {
340
- const rel = relative2(projectRoot, file).split("\\").join("/");
341
- let text;
342
- try {
343
- text = readFileSync3(file, "utf8");
344
- } catch {
345
- continue;
346
- }
336
+ for (const { path, text } of files) {
347
337
  if (hasGeneratedBanner(text)) continue;
348
338
  const lines = text.split(/\r?\n/);
349
339
  for (let i = 0; i < lines.length; i += 1) {
350
340
  if (!isOffendingSink(lines, i)) continue;
351
- findings.push(`${rel}:${i + 1} \u2014 ${truncate(lines[i])}`);
341
+ findings.push(`${path}:${i + 1} \u2014 ${truncate(lines[i])}`);
352
342
  }
353
343
  }
354
- if (findings.length === 0) {
355
- return [
356
- COOKIE(
357
- "pass",
358
- "no domain-scoped Set-Cookie or document.cookie writes in app-authored src/ (generated output skipped)"
359
- )
360
- ];
344
+ if (findings.length > 0) {
345
+ return [COOKIE("fail", `${findings.join("; ")}; ${REMEDIATION}`)];
346
+ }
347
+ if (unreadable) {
348
+ return [COOKIE("skip", "one or more source files could not be read")];
349
+ }
350
+ return [
351
+ COOKIE(
352
+ "pass",
353
+ "no domain-scoped Set-Cookie or document.cookie writes in app-authored src/ (generated output skipped)"
354
+ )
355
+ ];
356
+ }
357
+ function checkCookieCodecConformance(projectRoot) {
358
+ const srcDir = join2(projectRoot, "src");
359
+ if (!existsSync2(srcDir)) return checkCookieSourceText([], false, false);
360
+ const files = [];
361
+ walkSourceFiles(srcDir, files);
362
+ const textFiles = [];
363
+ let unreadable = false;
364
+ for (const file of files) {
365
+ const rel = relative2(projectRoot, file).split("\\").join("/");
366
+ try {
367
+ textFiles.push({ path: rel, text: readFileSync3(file, "utf8") });
368
+ } catch {
369
+ unreadable = true;
370
+ }
361
371
  }
362
- return [COOKIE("fail", `${findings.join("; ")}; ${REMEDIATION}`)];
372
+ return checkCookieSourceText(textFiles, true, unreadable);
363
373
  }
364
374
 
365
375
  // src/doctor/probe.ts
@@ -1,4 +1,4 @@
1
- import { S as Schemas } from './_spec-Cz-yijWv.js';
1
+ import { S as Schemas } from './_spec-C4T68Nnr.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-Cz-yijWv.mjs';
1
+ import { S as Schemas } from './_spec-C4T68Nnr.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-Cz-yijWv.mjs';
2
- import { L as ListEnvelope, s as RelatedSearch, a as CustomFieldFilter, O as ObjectReferenceFilter } from './jobs-DCeOWaPk.mjs';
1
+ import { S as Schemas } from './_spec-C4T68Nnr.js';
2
+ import { L as ListEnvelope, t as RelatedSearch, a as CustomFieldFilter, O as ObjectReferenceFilter } from './jobs-3Md7CCMl.js';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /** A market (sector) a company operates in — name + its source slug. */
@@ -123,6 +123,14 @@ type PublicBoardFeatures = PublicBoard['features'];
123
123
  type PublicBoardAnalytics = PublicBoard['analytics'];
124
124
  type PublicBoardAds = PublicBoard['ads'];
125
125
  type PublicBoardJobForm = PublicBoard['jobForm'];
126
+ /**
127
+ * One of the board's custom employment types from
128
+ * `board.context().jobForm.employmentType.customTypes`. Offer it in the
129
+ * posting form next to the built-ins when `offered` is true, in
130
+ * `jobForm.employmentType.order`; send `key` as `customEmploymentType`
131
+ * and `employmentType` (its built-in Google equivalent) together.
132
+ */
133
+ type BoardCustomEmploymentType = Schemas['BoardCustomEmploymentType'];
126
134
  /**
127
135
  * Sign-in options per role from `board.context().signIn`: which built-in
128
136
  * methods to offer and the board's SSO connections. Render the sign-in page
@@ -165,4 +173,4 @@ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
165
173
  type CustomFieldType = CustomFieldDefinition['type'];
166
174
  type CustomFieldOption = Schemas['CustomFieldOption'];
167
175
 
168
- export type { PublicBoardJobForm as A, BoardFormBuiltinField as B, CustomFieldDefinition as C, PublicBoardSignIn as D, PublicCompany as E, PublicCompanyDetail as F, PublicCompanyMembership as G, SalaryCompany as H, SalaryLocation as I, SalarySkill as J, SalaryTitle as K, LocationSalaryDetail as L, SkillLocationSalary as M, SkillLocationsIndex as N, TitleLocationSalary as O, PublicBoard as P, TitleLocationsIndex as Q, 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, BoardFormField as j, BoardFormLayout as k, BoardFormLockReason as l, BoardJobFormField as m, BoardProfileFormField as n, BoardRoleSignIn as o, BoardSignInSsoConnection as p, CompanyMarket as q, CompanyMarketRef as r, CompanySalarySummary as s, CustomFieldOption as t, CustomFieldType as u, LocationSkillsIndex as v, LocationTitlesIndex as w, PublicBoardAds as x, PublicBoardAnalytics as y, PublicBoardFeatures as z };
176
+ export type { PublicBoardFeatures as A, BoardCustomEmploymentType as B, CustomFieldDefinition as C, PublicBoardJobForm as D, PublicBoardSignIn as E, PublicCompany as F, PublicCompanyDetail as G, PublicCompanyMembership as H, SalaryCompany as I, SalaryLocation as J, SalarySkill as K, LocationSalaryDetail as L, SalaryTitle as M, SkillLocationSalary as N, SkillLocationsIndex as O, PublicBoard as P, TitleLocationSalary as Q, TitleLocationsIndex as R, 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, BoardFormBuiltinField as j, BoardFormField as k, BoardFormLayout as l, BoardFormLockReason as m, BoardJobFormField as n, BoardProfileFormField as o, BoardRoleSignIn as p, BoardSignInSsoConnection as q, CompanyMarket as r, CompanyMarketRef as s, CompanySalarySummary as t, CustomFieldOption as u, CustomFieldType as v, LocationSkillsIndex as w, LocationTitlesIndex as x, PublicBoardAds as y, PublicBoardAnalytics as z };
@@ -1,5 +1,5 @@
1
- import { S as Schemas } from './_spec-Cz-yijWv.js';
2
- import { L as ListEnvelope, s as RelatedSearch, a as CustomFieldFilter, O as ObjectReferenceFilter } from './jobs-D0OqM6IS.js';
1
+ import { S as Schemas } from './_spec-C4T68Nnr.mjs';
2
+ import { L as ListEnvelope, t as RelatedSearch, a as CustomFieldFilter, O as ObjectReferenceFilter } from './jobs-Cg2d2oI4.mjs';
3
3
 
4
4
  type PublicCompany = Schemas['CompanyPublic'];
5
5
  /** A market (sector) a company operates in — name + its source slug. */
@@ -123,6 +123,14 @@ type PublicBoardFeatures = PublicBoard['features'];
123
123
  type PublicBoardAnalytics = PublicBoard['analytics'];
124
124
  type PublicBoardAds = PublicBoard['ads'];
125
125
  type PublicBoardJobForm = PublicBoard['jobForm'];
126
+ /**
127
+ * One of the board's custom employment types from
128
+ * `board.context().jobForm.employmentType.customTypes`. Offer it in the
129
+ * posting form next to the built-ins when `offered` is true, in
130
+ * `jobForm.employmentType.order`; send `key` as `customEmploymentType`
131
+ * and `employmentType` (its built-in Google equivalent) together.
132
+ */
133
+ type BoardCustomEmploymentType = Schemas['BoardCustomEmploymentType'];
126
134
  /**
127
135
  * Sign-in options per role from `board.context().signIn`: which built-in
128
136
  * methods to offer and the board's SSO connections. Render the sign-in page
@@ -165,4 +173,4 @@ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
165
173
  type CustomFieldType = CustomFieldDefinition['type'];
166
174
  type CustomFieldOption = Schemas['CustomFieldOption'];
167
175
 
168
- export type { PublicBoardJobForm as A, BoardFormBuiltinField as B, CustomFieldDefinition as C, PublicBoardSignIn as D, PublicCompany as E, PublicCompanyDetail as F, PublicCompanyMembership as G, SalaryCompany as H, SalaryLocation as I, SalarySkill as J, SalaryTitle as K, LocationSalaryDetail as L, SkillLocationSalary as M, SkillLocationsIndex as N, TitleLocationSalary as O, PublicBoard as P, TitleLocationsIndex as Q, 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, BoardFormField as j, BoardFormLayout as k, BoardFormLockReason as l, BoardJobFormField as m, BoardProfileFormField as n, BoardRoleSignIn as o, BoardSignInSsoConnection as p, CompanyMarket as q, CompanyMarketRef as r, CompanySalarySummary as s, CustomFieldOption as t, CustomFieldType as u, LocationSkillsIndex as v, LocationTitlesIndex as w, PublicBoardAds as x, PublicBoardAnalytics as y, PublicBoardFeatures as z };
176
+ export type { PublicBoardFeatures as A, BoardCustomEmploymentType as B, CustomFieldDefinition as C, PublicBoardJobForm as D, PublicBoardSignIn as E, PublicCompany as F, PublicCompanyDetail as G, PublicCompanyMembership as H, SalaryCompany as I, SalaryLocation as J, SalarySkill as K, LocationSalaryDetail as L, SalaryTitle as M, SkillLocationSalary as N, SkillLocationsIndex as O, PublicBoard as P, TitleLocationSalary as Q, TitleLocationsIndex as R, 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, BoardFormBuiltinField as j, BoardFormField as k, BoardFormLayout as l, BoardFormLockReason as m, BoardJobFormField as n, BoardProfileFormField as o, BoardRoleSignIn as p, BoardSignInSsoConnection as q, CompanyMarket as r, CompanyMarketRef as s, CompanySalarySummary as t, CustomFieldOption as u, CustomFieldType as v, LocationSkillsIndex as w, LocationTitlesIndex as x, PublicBoardAds as y, PublicBoardAnalytics 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-Dlv-nGl3.js';
2
- import { P as PublicJob } from './jobs-D0OqM6IS.js';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-2UfZ7fZk.js';
2
+ import { P as PublicJob } from './jobs-3Md7CCMl.js';
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-BKUGfCIT.mjs';
2
- import { P as PublicJob } from './jobs-DCeOWaPk.mjs';
1
+ import { P as PublicBoard, a as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './board-CRgQjnrn.mjs';
2
+ import { P as PublicJob } from './jobs-Cg2d2oI4.mjs';
3
3
 
4
4
  /**
5
5
  * Wire enum for `salaryTimeframe`. Defined here (not re-exported from any