@cavuno/board 1.30.0 → 1.31.0-preview.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.
@@ -0,0 +1,17 @@
1
+ import { b as Schemas } from './jobs-Dmz8uexp.js';
2
+
3
+ type PublicBoard = Schemas['PublicBoardContext'];
4
+ type PublicBoardFeatures = PublicBoard['features'];
5
+ type PublicBoardAnalytics = PublicBoard['analytics'];
6
+ type PublicBoardTheme = NonNullable<PublicBoard['theme']>;
7
+ /**
8
+ * An operator-defined custom job-field definition (CAV-294). Board-wide;
9
+ * use it to render and localize a job's opaque `customFieldValues` (resolve
10
+ * option `key`s → labels, honour field `type` and display order). Shared with
11
+ * the Operator API's custom-field surface (one canonical schema).
12
+ */
13
+ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
14
+ type CustomFieldType = CustomFieldDefinition['type'];
15
+ type CustomFieldOption = Schemas['CustomFieldOption'];
16
+
17
+ export type { CustomFieldDefinition as C, PublicBoard as P, CustomFieldOption as a, CustomFieldType as b, PublicBoardAnalytics as c, PublicBoardFeatures as d, PublicBoardTheme as e };
@@ -0,0 +1,17 @@
1
+ import { b as Schemas } from './jobs-Dmz8uexp.mjs';
2
+
3
+ type PublicBoard = Schemas['PublicBoardContext'];
4
+ type PublicBoardFeatures = PublicBoard['features'];
5
+ type PublicBoardAnalytics = PublicBoard['analytics'];
6
+ type PublicBoardTheme = NonNullable<PublicBoard['theme']>;
7
+ /**
8
+ * An operator-defined custom job-field definition (CAV-294). Board-wide;
9
+ * use it to render and localize a job's opaque `customFieldValues` (resolve
10
+ * option `key`s → labels, honour field `type` and display order). Shared with
11
+ * the Operator API's custom-field surface (one canonical schema).
12
+ */
13
+ type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
14
+ type CustomFieldType = CustomFieldDefinition['type'];
15
+ type CustomFieldOption = Schemas['CustomFieldOption'];
16
+
17
+ export type { CustomFieldDefinition as C, PublicBoard as P, CustomFieldOption as a, CustomFieldType as b, PublicBoardAnalytics as c, PublicBoardFeatures as d, PublicBoardTheme as e };
@@ -1,4 +1,4 @@
1
- import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-lzeoVGY6.mjs';
1
+ import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-Dmz8uexp.mjs';
2
2
 
3
3
  declare const REMOTE_OPTIONS: readonly RemoteOption[];
4
4
  /**
package/dist/filters.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-lzeoVGY6.js';
1
+ import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-Dmz8uexp.js';
2
2
 
3
3
  declare const REMOTE_OPTIONS: readonly RemoteOption[];
4
4
  /**
package/dist/format.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- import { P as PublicJob, a as PublicJobCard } from './jobs-lzeoVGY6.mjs';
1
+ import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-Dmz8uexp.mjs';
2
+ import { C as CustomFieldDefinition } from './board-BS8Ax7hz.mjs';
2
3
 
3
4
  /**
4
5
  * Date display helpers in the board language (required leading parameter,
@@ -237,4 +238,31 @@ interface SalaryTimeframeOverrides {
237
238
  */
238
239
  declare function formatSalaryRange(language: string | undefined, min: number | null, max: number | null, timeframe: SalaryTimeframeInput, currency?: string | null, timeframeOverrides?: SalaryTimeframeOverrides): string | null;
239
240
 
240
- export { type SalaryFrames, type SalaryLexicon, type SalaryTimeframeInput, type SalaryTimeframeOverrides, type SalaryTimeframeValue, type SeniorityKey, cardLocationLabel, fieldLabel, formatDate, formatMonthYear, formatPublishedRelativeDate, formatSalaryRange, fullJobToCard, getSalaryLexicon, locationLabel };
241
+ declare function companyIntro(summary: string | null, description: string | null): string | null;
242
+
243
+ /**
244
+ * Resolve a job's opaque `customFieldValues` into ordered, display-ready
245
+ * entries for the "Additional details" section — the client-side twin of the
246
+ * hosted `resolveCustomFieldDisplay` (apps/web/lib/jobs/job-form-config/
247
+ * custom-field-display.ts). Pure. Iterates the *definitions* (from board
248
+ * context) in config order, so display order is operator-controlled, orphan
249
+ * values (deleted definitions) are never inspected, and empty values drop per
250
+ * field. Select values resolve their stored option KEY to the current label
251
+ * (rename-safe); an option with no current match is dropped. Booleans stay raw
252
+ * (a discriminated `kind`) — the render layer authors the "Yes"/"No" chrome
253
+ * (English; localized copy is the use-intl follow-up).
254
+ */
255
+ type CustomFieldDisplayEntry = {
256
+ key: string;
257
+ label: string;
258
+ kind: 'text';
259
+ value: string;
260
+ } | {
261
+ key: string;
262
+ label: string;
263
+ kind: 'boolean';
264
+ value: boolean;
265
+ };
266
+ declare function resolveCustomFieldDisplay(definitions: CustomFieldDefinition[] | undefined, values: CustomFieldValues | undefined): CustomFieldDisplayEntry[];
267
+
268
+ export { type CustomFieldDisplayEntry, type SalaryFrames, type SalaryLexicon, type SalaryTimeframeInput, type SalaryTimeframeOverrides, type SalaryTimeframeValue, type SeniorityKey, cardLocationLabel, companyIntro, fieldLabel, formatDate, formatMonthYear, formatPublishedRelativeDate, formatSalaryRange, fullJobToCard, getSalaryLexicon, locationLabel, resolveCustomFieldDisplay };
package/dist/format.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { P as PublicJob, a as PublicJobCard } from './jobs-lzeoVGY6.js';
1
+ import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-Dmz8uexp.js';
2
+ import { C as CustomFieldDefinition } from './board--nLjpneU.js';
2
3
 
3
4
  /**
4
5
  * Date display helpers in the board language (required leading parameter,
@@ -237,4 +238,31 @@ interface SalaryTimeframeOverrides {
237
238
  */
238
239
  declare function formatSalaryRange(language: string | undefined, min: number | null, max: number | null, timeframe: SalaryTimeframeInput, currency?: string | null, timeframeOverrides?: SalaryTimeframeOverrides): string | null;
239
240
 
240
- export { type SalaryFrames, type SalaryLexicon, type SalaryTimeframeInput, type SalaryTimeframeOverrides, type SalaryTimeframeValue, type SeniorityKey, cardLocationLabel, fieldLabel, formatDate, formatMonthYear, formatPublishedRelativeDate, formatSalaryRange, fullJobToCard, getSalaryLexicon, locationLabel };
241
+ declare function companyIntro(summary: string | null, description: string | null): string | null;
242
+
243
+ /**
244
+ * Resolve a job's opaque `customFieldValues` into ordered, display-ready
245
+ * entries for the "Additional details" section — the client-side twin of the
246
+ * hosted `resolveCustomFieldDisplay` (apps/web/lib/jobs/job-form-config/
247
+ * custom-field-display.ts). Pure. Iterates the *definitions* (from board
248
+ * context) in config order, so display order is operator-controlled, orphan
249
+ * values (deleted definitions) are never inspected, and empty values drop per
250
+ * field. Select values resolve their stored option KEY to the current label
251
+ * (rename-safe); an option with no current match is dropped. Booleans stay raw
252
+ * (a discriminated `kind`) — the render layer authors the "Yes"/"No" chrome
253
+ * (English; localized copy is the use-intl follow-up).
254
+ */
255
+ type CustomFieldDisplayEntry = {
256
+ key: string;
257
+ label: string;
258
+ kind: 'text';
259
+ value: string;
260
+ } | {
261
+ key: string;
262
+ label: string;
263
+ kind: 'boolean';
264
+ value: boolean;
265
+ };
266
+ declare function resolveCustomFieldDisplay(definitions: CustomFieldDefinition[] | undefined, values: CustomFieldValues | undefined): CustomFieldDisplayEntry[];
267
+
268
+ export { type CustomFieldDisplayEntry, type SalaryFrames, type SalaryLexicon, type SalaryTimeframeInput, type SalaryTimeframeOverrides, type SalaryTimeframeValue, type SeniorityKey, cardLocationLabel, companyIntro, fieldLabel, formatDate, formatMonthYear, formatPublishedRelativeDate, formatSalaryRange, fullJobToCard, getSalaryLexicon, locationLabel, resolveCustomFieldDisplay };
package/dist/format.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var format_exports = {};
22
22
  __export(format_exports, {
23
23
  cardLocationLabel: () => cardLocationLabel,
24
+ companyIntro: () => companyIntro,
24
25
  fieldLabel: () => fieldLabel,
25
26
  formatDate: () => formatDate,
26
27
  formatMonthYear: () => formatMonthYear,
@@ -28,7 +29,8 @@ __export(format_exports, {
28
29
  formatSalaryRange: () => formatSalaryRange,
29
30
  fullJobToCard: () => fullJobToCard,
30
31
  getSalaryLexicon: () => getSalaryLexicon,
31
- locationLabel: () => locationLabel
32
+ locationLabel: () => locationLabel,
33
+ resolveCustomFieldDisplay: () => resolveCustomFieldDisplay
32
34
  });
33
35
  module.exports = __toCommonJS(format_exports);
34
36
 
@@ -451,3 +453,76 @@ function formatSalaryRange(language, min, max, timeframe, currency = null, timef
451
453
  timeframeLabel
452
454
  );
453
455
  }
456
+
457
+ // src/format/company-intro.ts
458
+ var NAMED_ENTITIES = {
459
+ amp: "&",
460
+ lt: "<",
461
+ gt: ">",
462
+ quot: '"',
463
+ apos: "'",
464
+ nbsp: " "
465
+ };
466
+ function decodeEntities(input) {
467
+ return input.replace(/&(#\d+|#x[0-9a-f]+|[a-z]+);/gi, (match, body) => {
468
+ const token = String(body);
469
+ if (token[0] === "#") {
470
+ const code = token[1] === "x" || token[1] === "X" ? parseInt(token.slice(2), 16) : parseInt(token.slice(1), 10);
471
+ if (!Number.isInteger(code) || code < 0 || code > 1114111) return match;
472
+ return String.fromCodePoint(code);
473
+ }
474
+ return NAMED_ENTITIES[token.toLowerCase()] ?? match;
475
+ });
476
+ }
477
+ function companyIntro(summary, description) {
478
+ const trimmedSummary = summary?.trim();
479
+ if (trimmedSummary) return trimmedSummary;
480
+ if (!description) return null;
481
+ const text = decodeEntities(
482
+ description.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<\/(p|div|li|h[1-6])>/gi, " ").replace(/<[^>]*>/g, "")
483
+ ).replace(/\s+/g, " ").trim();
484
+ if (!text) return null;
485
+ const [first] = text.split(/(?<=[.!?])\s+/);
486
+ return first ?? text;
487
+ }
488
+
489
+ // src/format/custom-fields.ts
490
+ function renderTextValue(def, raw) {
491
+ switch (def.type) {
492
+ case "number":
493
+ return typeof raw === "number" ? String(raw) : null;
494
+ case "single_select": {
495
+ if (typeof raw !== "string") return null;
496
+ return def.options?.find((o) => o.key === raw)?.label ?? null;
497
+ }
498
+ case "multi_select": {
499
+ if (!Array.isArray(raw) || raw.length === 0) return null;
500
+ const labels = raw.map((key) => def.options?.find((o) => o.key === key)?.label).filter((label) => Boolean(label));
501
+ return labels.length > 0 ? labels.join(", ") : null;
502
+ }
503
+ default:
504
+ return typeof raw === "string" && raw.trim() !== "" ? raw : null;
505
+ }
506
+ }
507
+ function resolveCustomFieldDisplay(definitions, values) {
508
+ const entries = [];
509
+ for (const def of definitions ?? []) {
510
+ const raw = values?.[def.key];
511
+ if (def.type === "boolean") {
512
+ if (typeof raw === "boolean") {
513
+ entries.push({
514
+ key: def.key,
515
+ label: def.label,
516
+ kind: "boolean",
517
+ value: raw
518
+ });
519
+ }
520
+ continue;
521
+ }
522
+ const value = renderTextValue(def, raw);
523
+ if (value !== null) {
524
+ entries.push({ key: def.key, label: def.label, kind: "text", value });
525
+ }
526
+ }
527
+ return entries;
528
+ }
package/dist/format.mjs CHANGED
@@ -417,8 +417,82 @@ function formatSalaryRange(language, min, max, timeframe, currency = null, timef
417
417
  timeframeLabel
418
418
  );
419
419
  }
420
+
421
+ // src/format/company-intro.ts
422
+ var NAMED_ENTITIES = {
423
+ amp: "&",
424
+ lt: "<",
425
+ gt: ">",
426
+ quot: '"',
427
+ apos: "'",
428
+ nbsp: " "
429
+ };
430
+ function decodeEntities(input) {
431
+ return input.replace(/&(#\d+|#x[0-9a-f]+|[a-z]+);/gi, (match, body) => {
432
+ const token = String(body);
433
+ if (token[0] === "#") {
434
+ const code = token[1] === "x" || token[1] === "X" ? parseInt(token.slice(2), 16) : parseInt(token.slice(1), 10);
435
+ if (!Number.isInteger(code) || code < 0 || code > 1114111) return match;
436
+ return String.fromCodePoint(code);
437
+ }
438
+ return NAMED_ENTITIES[token.toLowerCase()] ?? match;
439
+ });
440
+ }
441
+ function companyIntro(summary, description) {
442
+ const trimmedSummary = summary?.trim();
443
+ if (trimmedSummary) return trimmedSummary;
444
+ if (!description) return null;
445
+ const text = decodeEntities(
446
+ description.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<br\s*\/?>/gi, " ").replace(/<\/(p|div|li|h[1-6])>/gi, " ").replace(/<[^>]*>/g, "")
447
+ ).replace(/\s+/g, " ").trim();
448
+ if (!text) return null;
449
+ const [first] = text.split(/(?<=[.!?])\s+/);
450
+ return first ?? text;
451
+ }
452
+
453
+ // src/format/custom-fields.ts
454
+ function renderTextValue(def, raw) {
455
+ switch (def.type) {
456
+ case "number":
457
+ return typeof raw === "number" ? String(raw) : null;
458
+ case "single_select": {
459
+ if (typeof raw !== "string") return null;
460
+ return def.options?.find((o) => o.key === raw)?.label ?? null;
461
+ }
462
+ case "multi_select": {
463
+ if (!Array.isArray(raw) || raw.length === 0) return null;
464
+ const labels = raw.map((key) => def.options?.find((o) => o.key === key)?.label).filter((label) => Boolean(label));
465
+ return labels.length > 0 ? labels.join(", ") : null;
466
+ }
467
+ default:
468
+ return typeof raw === "string" && raw.trim() !== "" ? raw : null;
469
+ }
470
+ }
471
+ function resolveCustomFieldDisplay(definitions, values) {
472
+ const entries = [];
473
+ for (const def of definitions ?? []) {
474
+ const raw = values?.[def.key];
475
+ if (def.type === "boolean") {
476
+ if (typeof raw === "boolean") {
477
+ entries.push({
478
+ key: def.key,
479
+ label: def.label,
480
+ kind: "boolean",
481
+ value: raw
482
+ });
483
+ }
484
+ continue;
485
+ }
486
+ const value = renderTextValue(def, raw);
487
+ if (value !== null) {
488
+ entries.push({ key: def.key, label: def.label, kind: "text", value });
489
+ }
490
+ }
491
+ return entries;
492
+ }
420
493
  export {
421
494
  cardLocationLabel,
495
+ companyIntro,
422
496
  fieldLabel,
423
497
  formatDate,
424
498
  formatMonthYear,
@@ -426,5 +500,6 @@ export {
426
500
  formatSalaryRange,
427
501
  fullJobToCard,
428
502
  getSalaryLexicon,
429
- locationLabel
503
+ locationLabel,
504
+ resolveCustomFieldDisplay
430
505
  };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,8 @@
1
- import { b as Schemas, R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, c as components, d as JobsListQuery, e as JobCardListEnvelope, f as JobsSearchBody, g as JobCardSearchEnvelope, h as JobsSimilarQuery, i as SearchEnvelope } from './jobs-lzeoVGY6.mjs';
2
- export { C as CustomFieldValue, j as CustomFieldValues, k as EducationRequirement, l as JobCompany, J as JobSort, O as OfficeLocation, P as PublicJob, a as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-lzeoVGY6.mjs';
3
- import { c as CompaniesListQuery, d as CompanyListEnvelope, e as CompaniesSearchBody, f as CompanyJobsListQuery, g as CompanySimilarQuery, h as CompanyMarketsListQuery, i as SalaryDetailQuery, j as BlogPostsListQuery, k as BlogSimilarQuery, l as BlogSearchBody } from './salaries-DpH5CxdM.mjs';
4
- export { B as BlogAuthorEmbed, m as BlogTagEmbed, C as CompanyCategorySalary, n as CompanyMarket, o as CompanyMarketRef, b as CompanySalary, p as CustomFieldDefinition, q as CustomFieldOption, r as CustomFieldType, L as LocationSalaryDetail, s as LocationSkillsIndex, t as LocationTitlesIndex, u as PublicBlogAdjacentPosts, v as PublicBlogAuthor, w as PublicBlogPost, a as PublicBlogPostSummary, x as PublicBlogTag, P as PublicBoard, y as PublicBoardAnalytics, z as PublicBoardFeatures, A as PublicBoardTheme, D as PublicCompany, E as PublicCompanyDetail, F as SalaryCompany, G as SalaryLocation, H as SalarySkill, I as SalaryTitle, J as SkillLocationSalary, K as SkillLocationsIndex, S as SkillSalaryDetail, M as TitleLocationSalary, N as TitleLocationsIndex, T as TitleSalaryDetail } from './salaries-DpH5CxdM.mjs';
1
+ import { b as Schemas, R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, c as components, d as JobsListQuery, e as JobCardListEnvelope, f as JobsSearchBody, g as JobCardSearchEnvelope, h as JobsSimilarQuery, i as SearchEnvelope } from './jobs-Dmz8uexp.mjs';
2
+ export { j as CustomFieldValue, C as CustomFieldValues, k as EducationRequirement, l as JobCompany, J as JobSort, O as OfficeLocation, P as PublicJob, a as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-Dmz8uexp.mjs';
3
+ export { C as CustomFieldDefinition, a as CustomFieldOption, b as CustomFieldType, P as PublicBoard, c as PublicBoardAnalytics, d as PublicBoardFeatures, e as PublicBoardTheme } from './board-BS8Ax7hz.mjs';
4
+ import { b as CompaniesListQuery, c as CompanyListEnvelope, d as CompaniesSearchBody, e as CompanyJobsListQuery, f as CompanySimilarQuery, g as CompanyMarketsListQuery, h as SalaryDetailQuery, i as BlogPostsListQuery, j as BlogSimilarQuery, k as BlogSearchBody } from './salaries-QXFAyysR.mjs';
5
+ export { B as BlogAuthorEmbed, l as BlogTagEmbed, C as CompanyCategorySalary, m as CompanyMarket, n as CompanyMarketRef, a as CompanySalary, L as LocationSalaryDetail, o as LocationSkillsIndex, p as LocationTitlesIndex, q as PublicBlogAdjacentPosts, r as PublicBlogAuthor, s as PublicBlogPost, P as PublicBlogPostSummary, t as PublicBlogTag, u as PublicCompany, v as PublicCompanyDetail, w as SalaryCompany, x as SalaryLocation, y as SalarySkill, z as SalaryTitle, A as SkillLocationSalary, D as SkillLocationsIndex, S as SkillSalaryDetail, E as TitleLocationSalary, F as TitleLocationsIndex, T as TitleSalaryDetail } from './salaries-QXFAyysR.mjs';
5
6
 
6
7
  type Awaitable<T> = T | Promise<T>;
7
8
  /**
@@ -203,7 +204,7 @@ declare function paginate<Q extends Record<string, unknown>, P extends PageShape
203
204
  * constant because the package is platform-neutral and cannot read
204
205
  * package.json at runtime.
205
206
  */
206
- declare const SDK_VERSION = "1.30.0";
207
+ declare const SDK_VERSION = "1.31.0-preview.0";
207
208
 
208
209
  type SavedJob = Schemas['SavedJob'];
209
210
  type SavedJobsListQuery = {
@@ -382,6 +383,47 @@ declare function isColdRule(messages: Message[], counterpartyId: string): boolea
382
383
  /** The id of the viewer's most recent message (the only one that shows "Seen"). */
383
384
  declare function lastOwnMessageId(messages: Message[], counterpartyId: string): string | null;
384
385
 
386
+ /**
387
+ * The apply-decision ladder (ADR-0054) as a pure function — a core-entry
388
+ * derive export like `messaging-derive`, so security/logic fixes ship via
389
+ * the versioned package instead of re-copied registry files. Unit-testable
390
+ * independent of React. Mirrors the hosted board's rule: an external
391
+ * `applicationUrl`, when present, is the apply path for EVERYONE — it is
392
+ * never gated behind auth or verification, so a signed-in-but-unverified
393
+ * candidate is never worse off than an anonymous visitor.
394
+ */
395
+ type ApplyAction = {
396
+ kind: 'external';
397
+ url: string;
398
+ } | {
399
+ kind: 'sign-in';
400
+ } | {
401
+ kind: 'verify-email';
402
+ } | {
403
+ kind: 'native';
404
+ jobSlug: string;
405
+ } | {
406
+ kind: 'applied';
407
+ } | {
408
+ kind: 'none';
409
+ };
410
+ /**
411
+ * A job's `applicationUrl` is operator/submitter-controlled and reaches
412
+ * this component through the public API, so it can carry a dangerous
413
+ * scheme (`javascript:`, `data:`, `vbscript:`) that would execute when
414
+ * rendered as an `<a href>`. Only http(s) and mailto are safe apply
415
+ * targets; anything else is treated as no external URL at all.
416
+ */
417
+ declare function isSafeApplicationUrl(url: string): boolean;
418
+ declare function resolveApplyAction(state: {
419
+ jobSlug: string | null;
420
+ applicationUrl: string | null;
421
+ viewer: {
422
+ emailVerified: boolean;
423
+ } | null;
424
+ applied: boolean;
425
+ }): ApplyAction;
426
+
385
427
  type BoardUser = Schemas['BoardUser'];
386
428
  type BoardAuthSession = Schemas['BoardAuthSession'];
387
429
  type RegisterBody = Schemas['BoardAuthRegisterBody'];
@@ -2893,4 +2935,4 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
2893
2935
  };
2894
2936
  type BoardSdk = ReturnType<typeof createBoardClient>;
2895
2937
 
2896
- export { ACCESS_TOKEN_KEY, type AccessCheckoutBody, type AccessCheckoutSession, type AccessCheckoutSessionState, type AccessGrant, type AccessPortalBody, type AccessPortalSession, type AddApplicantNoteBody, type Alert, type AlertBody, type Application, type ApplicationsListQuery, type ApplyBody, type Awaitable, BOARD_ACCESS_GRANT_KEY, BOARD_API_ERROR_CODES, type Block, type BlockStatus, type BlockUserBody, type BlockedUser, BlogPostsListQuery, BlogSearchBody, BlogSimilarQuery, type BoardAccessGrant, BoardApiError, type BoardApiErrorCode, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardSeo, type BoardUser, type BulkMoveApplicantsBody, type BulkRejectApplicantsBody, type CandidateAvatar, type CandidateEducation, type CandidateExperience, type CandidateLanguage, type CandidateProfile, type CandidateSkill, type ClaimableCompany, CompaniesListQuery, CompaniesSearchBody, CompanyJobsListQuery, CompanyListEnvelope, CompanyMarketsListQuery, type CompanyMembership, CompanySimilarQuery, type ConfirmWorkEmailBody, type ConsumeMagicLinkBody, type Conversation, type ConversationArchive, type ConversationDetail, type ConversationRef, type ConversationsListQuery, type CreateBoardClientOptions, type CreateCompanyBody, type CreateEducationBody, type CreateEmployerJobBody, type CreateExperienceBody, type CreateJobPostingInput, type CreatePipelineStageBody, type CustomStorage, type EditMessageBody, type EmbedJobsQuery, type EmployerApplicant, type EmployerBillingOption, type EmployerCheckout, type EmployerCheckoutBody, type EmployerCompany, type EmployerCompanySearchQuery, type EmployerJob, type EmployerJobSummary, type EmployerJobsListQuery, type EmployerPipeline, type EmployerPipelineQuery, type EmployerPipelineStage, EmploymentType, type FetchOptions, type FindExistingConversationQuery, type ForgotPasswordBody, type HandleAvailability, type JobAlertConfirmation, type JobAlertDeletePreferenceInput, type JobAlertFiltersInput, type JobAlertFrequency, type JobAlertManageQuery, type JobAlertManageResult, type JobAlertManageState, type JobAlertManageTokenInput, type JobAlertPreference, type JobAlertRemoteOption, type JobAlertResendResult, type JobAlertStoredFilters, type JobAlertSubscribeInput, type JobAlertSubscription, type JobAlertUpdatePreferenceInput, JobCardListEnvelope, JobCardSearchEnvelope, type JobPostingBillingCheck, type JobPostingBillingOptions, type JobPostingBillingVerification, type JobPostingLogoResult, type JobPostingPlan, type JobPostingResult, type JobPostingSubscriptionEntitlements, JobsListQuery, JobsSearchBody, JobsSimilarQuery, type LegalEntity, type LegalPageType, ListEnvelope, type Logger, type LoginBody, type LogoutBody, type Message, type ModerationReport, type MoveApplicantStageBody, type NotificationPreference, type OAuthAuthorizationQuery, type OAuthAuthorizationUrl, type OAuthExchangeBody, type OAuthProvider, type Paginator, type PaywallOffer, type PaywallOfferListEnvelope, type PlacesListQuery, type Plan, type PlanListEnvelope, type PlansListQuery, type PublicLegalPage, type PublicPlace, REFRESH_TOKEN_KEY, type ReadReceipt, type RedirectResolution, type RefreshBody, type RegisterBody, RemoteOption, type ReorderPipelineStagesBody, type ReplyBody, type ReportBody, type RequestMagicLinkBody, type ResetPasswordBody, type Resume, type ResumeUploadOptions, SDK_VERSION, SalaryDetailQuery, type SalesLedPlan, type SalesLedPlanListEnvelope, type SaveJobBody, type SavedJob, type SavedJobsListQuery, SearchEnvelope, type SendWorkEmailBody, Seniority, type StartAboutApplicationBody, type StartConversationBody, type StorageMode, type TalentDirectoryEntry, type TalentDirectoryListEnvelope, type TalentDirectoryQuery, type TalentProfile, type TaxonomyGeo, type TaxonomyResolution, type ThreadMessagesQuery, type UnreadCount, type UnsubscribeBody, type UpdateApplicationFactsBody, type UpdateCandidateProfileBody, type UpdateEducationBody, type UpdateEmployerCompanyBody, type UpdateEmployerJobBody, type UpdateExperienceBody, type UpdateLanguagesBody, type UpdateNotificationPreferenceBody, type UpdatePipelineStageBody, type UpdateSkillsBody, type VerifyEmailBody, createBoardClient, isBoardApiError, isBoardPasswordRequired, isColdRule, isConflict, isForbidden, isNotFound, isOwnMessage, isRateLimited, isUnauthorized, isValidationError, lastOwnMessageId, paginate };
2938
+ export { ACCESS_TOKEN_KEY, type AccessCheckoutBody, type AccessCheckoutSession, type AccessCheckoutSessionState, type AccessGrant, type AccessPortalBody, type AccessPortalSession, type AddApplicantNoteBody, type Alert, type AlertBody, type Application, type ApplicationsListQuery, type ApplyAction, type ApplyBody, type Awaitable, BOARD_ACCESS_GRANT_KEY, BOARD_API_ERROR_CODES, type Block, type BlockStatus, type BlockUserBody, type BlockedUser, BlogPostsListQuery, BlogSearchBody, BlogSimilarQuery, type BoardAccessGrant, BoardApiError, type BoardApiErrorCode, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardSeo, type BoardUser, type BulkMoveApplicantsBody, type BulkRejectApplicantsBody, type CandidateAvatar, type CandidateEducation, type CandidateExperience, type CandidateLanguage, type CandidateProfile, type CandidateSkill, type ClaimableCompany, CompaniesListQuery, CompaniesSearchBody, CompanyJobsListQuery, CompanyListEnvelope, CompanyMarketsListQuery, type CompanyMembership, CompanySimilarQuery, type ConfirmWorkEmailBody, type ConsumeMagicLinkBody, type Conversation, type ConversationArchive, type ConversationDetail, type ConversationRef, type ConversationsListQuery, type CreateBoardClientOptions, type CreateCompanyBody, type CreateEducationBody, type CreateEmployerJobBody, type CreateExperienceBody, type CreateJobPostingInput, type CreatePipelineStageBody, type CustomStorage, type EditMessageBody, type EmbedJobsQuery, type EmployerApplicant, type EmployerBillingOption, type EmployerCheckout, type EmployerCheckoutBody, type EmployerCompany, type EmployerCompanySearchQuery, type EmployerJob, type EmployerJobSummary, type EmployerJobsListQuery, type EmployerPipeline, type EmployerPipelineQuery, type EmployerPipelineStage, EmploymentType, type FetchOptions, type FindExistingConversationQuery, type ForgotPasswordBody, type HandleAvailability, type JobAlertConfirmation, type JobAlertDeletePreferenceInput, type JobAlertFiltersInput, type JobAlertFrequency, type JobAlertManageQuery, type JobAlertManageResult, type JobAlertManageState, type JobAlertManageTokenInput, type JobAlertPreference, type JobAlertRemoteOption, type JobAlertResendResult, type JobAlertStoredFilters, type JobAlertSubscribeInput, type JobAlertSubscription, type JobAlertUpdatePreferenceInput, JobCardListEnvelope, JobCardSearchEnvelope, type JobPostingBillingCheck, type JobPostingBillingOptions, type JobPostingBillingVerification, type JobPostingLogoResult, type JobPostingPlan, type JobPostingResult, type JobPostingSubscriptionEntitlements, JobsListQuery, JobsSearchBody, JobsSimilarQuery, type LegalEntity, type LegalPageType, ListEnvelope, type Logger, type LoginBody, type LogoutBody, type Message, type ModerationReport, type MoveApplicantStageBody, type NotificationPreference, type OAuthAuthorizationQuery, type OAuthAuthorizationUrl, type OAuthExchangeBody, type OAuthProvider, type Paginator, type PaywallOffer, type PaywallOfferListEnvelope, type PlacesListQuery, type Plan, type PlanListEnvelope, type PlansListQuery, type PublicLegalPage, type PublicPlace, REFRESH_TOKEN_KEY, type ReadReceipt, type RedirectResolution, type RefreshBody, type RegisterBody, RemoteOption, type ReorderPipelineStagesBody, type ReplyBody, type ReportBody, type RequestMagicLinkBody, type ResetPasswordBody, type Resume, type ResumeUploadOptions, SDK_VERSION, SalaryDetailQuery, type SalesLedPlan, type SalesLedPlanListEnvelope, type SaveJobBody, type SavedJob, type SavedJobsListQuery, SearchEnvelope, type SendWorkEmailBody, Seniority, type StartAboutApplicationBody, type StartConversationBody, type StorageMode, type TalentDirectoryEntry, type TalentDirectoryListEnvelope, type TalentDirectoryQuery, type TalentProfile, type TaxonomyGeo, type TaxonomyResolution, type ThreadMessagesQuery, type UnreadCount, type UnsubscribeBody, type UpdateApplicationFactsBody, type UpdateCandidateProfileBody, type UpdateEducationBody, type UpdateEmployerCompanyBody, type UpdateEmployerJobBody, type UpdateExperienceBody, type UpdateLanguagesBody, type UpdateNotificationPreferenceBody, type UpdatePipelineStageBody, type UpdateSkillsBody, type VerifyEmailBody, createBoardClient, isBoardApiError, isBoardPasswordRequired, isColdRule, isConflict, isForbidden, isNotFound, isOwnMessage, isRateLimited, isSafeApplicationUrl, isUnauthorized, isValidationError, lastOwnMessageId, paginate, resolveApplyAction };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { b as Schemas, R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, c as components, d as JobsListQuery, e as JobCardListEnvelope, f as JobsSearchBody, g as JobCardSearchEnvelope, h as JobsSimilarQuery, i as SearchEnvelope } from './jobs-lzeoVGY6.js';
2
- export { C as CustomFieldValue, j as CustomFieldValues, k as EducationRequirement, l as JobCompany, J as JobSort, O as OfficeLocation, P as PublicJob, a as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-lzeoVGY6.js';
3
- import { c as CompaniesListQuery, d as CompanyListEnvelope, e as CompaniesSearchBody, f as CompanyJobsListQuery, g as CompanySimilarQuery, h as CompanyMarketsListQuery, i as SalaryDetailQuery, j as BlogPostsListQuery, k as BlogSimilarQuery, l as BlogSearchBody } from './salaries-Cy3MhZov.js';
4
- export { B as BlogAuthorEmbed, m as BlogTagEmbed, C as CompanyCategorySalary, n as CompanyMarket, o as CompanyMarketRef, b as CompanySalary, p as CustomFieldDefinition, q as CustomFieldOption, r as CustomFieldType, L as LocationSalaryDetail, s as LocationSkillsIndex, t as LocationTitlesIndex, u as PublicBlogAdjacentPosts, v as PublicBlogAuthor, w as PublicBlogPost, a as PublicBlogPostSummary, x as PublicBlogTag, P as PublicBoard, y as PublicBoardAnalytics, z as PublicBoardFeatures, A as PublicBoardTheme, D as PublicCompany, E as PublicCompanyDetail, F as SalaryCompany, G as SalaryLocation, H as SalarySkill, I as SalaryTitle, J as SkillLocationSalary, K as SkillLocationsIndex, S as SkillSalaryDetail, M as TitleLocationSalary, N as TitleLocationsIndex, T as TitleSalaryDetail } from './salaries-Cy3MhZov.js';
1
+ import { b as Schemas, R as RemoteOption, E as EmploymentType, S as Seniority, L as ListEnvelope, c as components, d as JobsListQuery, e as JobCardListEnvelope, f as JobsSearchBody, g as JobCardSearchEnvelope, h as JobsSimilarQuery, i as SearchEnvelope } from './jobs-Dmz8uexp.js';
2
+ export { j as CustomFieldValue, C as CustomFieldValues, k as EducationRequirement, l as JobCompany, J as JobSort, O as OfficeLocation, P as PublicJob, a as PublicJobCard, m as RelatedSearch, n as RemotePermit, o as RemoteTimezone, p as StorefrontPagination } from './jobs-Dmz8uexp.js';
3
+ export { C as CustomFieldDefinition, a as CustomFieldOption, b as CustomFieldType, P as PublicBoard, c as PublicBoardAnalytics, d as PublicBoardFeatures, e as PublicBoardTheme } from './board--nLjpneU.js';
4
+ import { b as CompaniesListQuery, c as CompanyListEnvelope, d as CompaniesSearchBody, e as CompanyJobsListQuery, f as CompanySimilarQuery, g as CompanyMarketsListQuery, h as SalaryDetailQuery, i as BlogPostsListQuery, j as BlogSimilarQuery, k as BlogSearchBody } from './salaries-CrtQBy81.js';
5
+ export { B as BlogAuthorEmbed, l as BlogTagEmbed, C as CompanyCategorySalary, m as CompanyMarket, n as CompanyMarketRef, a as CompanySalary, L as LocationSalaryDetail, o as LocationSkillsIndex, p as LocationTitlesIndex, q as PublicBlogAdjacentPosts, r as PublicBlogAuthor, s as PublicBlogPost, P as PublicBlogPostSummary, t as PublicBlogTag, u as PublicCompany, v as PublicCompanyDetail, w as SalaryCompany, x as SalaryLocation, y as SalarySkill, z as SalaryTitle, A as SkillLocationSalary, D as SkillLocationsIndex, S as SkillSalaryDetail, E as TitleLocationSalary, F as TitleLocationsIndex, T as TitleSalaryDetail } from './salaries-CrtQBy81.js';
5
6
 
6
7
  type Awaitable<T> = T | Promise<T>;
7
8
  /**
@@ -203,7 +204,7 @@ declare function paginate<Q extends Record<string, unknown>, P extends PageShape
203
204
  * constant because the package is platform-neutral and cannot read
204
205
  * package.json at runtime.
205
206
  */
206
- declare const SDK_VERSION = "1.30.0";
207
+ declare const SDK_VERSION = "1.31.0-preview.0";
207
208
 
208
209
  type SavedJob = Schemas['SavedJob'];
209
210
  type SavedJobsListQuery = {
@@ -382,6 +383,47 @@ declare function isColdRule(messages: Message[], counterpartyId: string): boolea
382
383
  /** The id of the viewer's most recent message (the only one that shows "Seen"). */
383
384
  declare function lastOwnMessageId(messages: Message[], counterpartyId: string): string | null;
384
385
 
386
+ /**
387
+ * The apply-decision ladder (ADR-0054) as a pure function — a core-entry
388
+ * derive export like `messaging-derive`, so security/logic fixes ship via
389
+ * the versioned package instead of re-copied registry files. Unit-testable
390
+ * independent of React. Mirrors the hosted board's rule: an external
391
+ * `applicationUrl`, when present, is the apply path for EVERYONE — it is
392
+ * never gated behind auth or verification, so a signed-in-but-unverified
393
+ * candidate is never worse off than an anonymous visitor.
394
+ */
395
+ type ApplyAction = {
396
+ kind: 'external';
397
+ url: string;
398
+ } | {
399
+ kind: 'sign-in';
400
+ } | {
401
+ kind: 'verify-email';
402
+ } | {
403
+ kind: 'native';
404
+ jobSlug: string;
405
+ } | {
406
+ kind: 'applied';
407
+ } | {
408
+ kind: 'none';
409
+ };
410
+ /**
411
+ * A job's `applicationUrl` is operator/submitter-controlled and reaches
412
+ * this component through the public API, so it can carry a dangerous
413
+ * scheme (`javascript:`, `data:`, `vbscript:`) that would execute when
414
+ * rendered as an `<a href>`. Only http(s) and mailto are safe apply
415
+ * targets; anything else is treated as no external URL at all.
416
+ */
417
+ declare function isSafeApplicationUrl(url: string): boolean;
418
+ declare function resolveApplyAction(state: {
419
+ jobSlug: string | null;
420
+ applicationUrl: string | null;
421
+ viewer: {
422
+ emailVerified: boolean;
423
+ } | null;
424
+ applied: boolean;
425
+ }): ApplyAction;
426
+
385
427
  type BoardUser = Schemas['BoardUser'];
386
428
  type BoardAuthSession = Schemas['BoardAuthSession'];
387
429
  type RegisterBody = Schemas['BoardAuthRegisterBody'];
@@ -2893,4 +2935,4 @@ declare function createBoardClient(options: CreateBoardClientOptions): {
2893
2935
  };
2894
2936
  type BoardSdk = ReturnType<typeof createBoardClient>;
2895
2937
 
2896
- export { ACCESS_TOKEN_KEY, type AccessCheckoutBody, type AccessCheckoutSession, type AccessCheckoutSessionState, type AccessGrant, type AccessPortalBody, type AccessPortalSession, type AddApplicantNoteBody, type Alert, type AlertBody, type Application, type ApplicationsListQuery, type ApplyBody, type Awaitable, BOARD_ACCESS_GRANT_KEY, BOARD_API_ERROR_CODES, type Block, type BlockStatus, type BlockUserBody, type BlockedUser, BlogPostsListQuery, BlogSearchBody, BlogSimilarQuery, type BoardAccessGrant, BoardApiError, type BoardApiErrorCode, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardSeo, type BoardUser, type BulkMoveApplicantsBody, type BulkRejectApplicantsBody, type CandidateAvatar, type CandidateEducation, type CandidateExperience, type CandidateLanguage, type CandidateProfile, type CandidateSkill, type ClaimableCompany, CompaniesListQuery, CompaniesSearchBody, CompanyJobsListQuery, CompanyListEnvelope, CompanyMarketsListQuery, type CompanyMembership, CompanySimilarQuery, type ConfirmWorkEmailBody, type ConsumeMagicLinkBody, type Conversation, type ConversationArchive, type ConversationDetail, type ConversationRef, type ConversationsListQuery, type CreateBoardClientOptions, type CreateCompanyBody, type CreateEducationBody, type CreateEmployerJobBody, type CreateExperienceBody, type CreateJobPostingInput, type CreatePipelineStageBody, type CustomStorage, type EditMessageBody, type EmbedJobsQuery, type EmployerApplicant, type EmployerBillingOption, type EmployerCheckout, type EmployerCheckoutBody, type EmployerCompany, type EmployerCompanySearchQuery, type EmployerJob, type EmployerJobSummary, type EmployerJobsListQuery, type EmployerPipeline, type EmployerPipelineQuery, type EmployerPipelineStage, EmploymentType, type FetchOptions, type FindExistingConversationQuery, type ForgotPasswordBody, type HandleAvailability, type JobAlertConfirmation, type JobAlertDeletePreferenceInput, type JobAlertFiltersInput, type JobAlertFrequency, type JobAlertManageQuery, type JobAlertManageResult, type JobAlertManageState, type JobAlertManageTokenInput, type JobAlertPreference, type JobAlertRemoteOption, type JobAlertResendResult, type JobAlertStoredFilters, type JobAlertSubscribeInput, type JobAlertSubscription, type JobAlertUpdatePreferenceInput, JobCardListEnvelope, JobCardSearchEnvelope, type JobPostingBillingCheck, type JobPostingBillingOptions, type JobPostingBillingVerification, type JobPostingLogoResult, type JobPostingPlan, type JobPostingResult, type JobPostingSubscriptionEntitlements, JobsListQuery, JobsSearchBody, JobsSimilarQuery, type LegalEntity, type LegalPageType, ListEnvelope, type Logger, type LoginBody, type LogoutBody, type Message, type ModerationReport, type MoveApplicantStageBody, type NotificationPreference, type OAuthAuthorizationQuery, type OAuthAuthorizationUrl, type OAuthExchangeBody, type OAuthProvider, type Paginator, type PaywallOffer, type PaywallOfferListEnvelope, type PlacesListQuery, type Plan, type PlanListEnvelope, type PlansListQuery, type PublicLegalPage, type PublicPlace, REFRESH_TOKEN_KEY, type ReadReceipt, type RedirectResolution, type RefreshBody, type RegisterBody, RemoteOption, type ReorderPipelineStagesBody, type ReplyBody, type ReportBody, type RequestMagicLinkBody, type ResetPasswordBody, type Resume, type ResumeUploadOptions, SDK_VERSION, SalaryDetailQuery, type SalesLedPlan, type SalesLedPlanListEnvelope, type SaveJobBody, type SavedJob, type SavedJobsListQuery, SearchEnvelope, type SendWorkEmailBody, Seniority, type StartAboutApplicationBody, type StartConversationBody, type StorageMode, type TalentDirectoryEntry, type TalentDirectoryListEnvelope, type TalentDirectoryQuery, type TalentProfile, type TaxonomyGeo, type TaxonomyResolution, type ThreadMessagesQuery, type UnreadCount, type UnsubscribeBody, type UpdateApplicationFactsBody, type UpdateCandidateProfileBody, type UpdateEducationBody, type UpdateEmployerCompanyBody, type UpdateEmployerJobBody, type UpdateExperienceBody, type UpdateLanguagesBody, type UpdateNotificationPreferenceBody, type UpdatePipelineStageBody, type UpdateSkillsBody, type VerifyEmailBody, createBoardClient, isBoardApiError, isBoardPasswordRequired, isColdRule, isConflict, isForbidden, isNotFound, isOwnMessage, isRateLimited, isUnauthorized, isValidationError, lastOwnMessageId, paginate };
2938
+ export { ACCESS_TOKEN_KEY, type AccessCheckoutBody, type AccessCheckoutSession, type AccessCheckoutSessionState, type AccessGrant, type AccessPortalBody, type AccessPortalSession, type AddApplicantNoteBody, type Alert, type AlertBody, type Application, type ApplicationsListQuery, type ApplyAction, type ApplyBody, type Awaitable, BOARD_ACCESS_GRANT_KEY, BOARD_API_ERROR_CODES, type Block, type BlockStatus, type BlockUserBody, type BlockedUser, BlogPostsListQuery, BlogSearchBody, BlogSimilarQuery, type BoardAccessGrant, BoardApiError, type BoardApiErrorCode, type BoardAuthSession, BoardClient, type BoardRequest, type BoardSdk, type BoardSeo, type BoardUser, type BulkMoveApplicantsBody, type BulkRejectApplicantsBody, type CandidateAvatar, type CandidateEducation, type CandidateExperience, type CandidateLanguage, type CandidateProfile, type CandidateSkill, type ClaimableCompany, CompaniesListQuery, CompaniesSearchBody, CompanyJobsListQuery, CompanyListEnvelope, CompanyMarketsListQuery, type CompanyMembership, CompanySimilarQuery, type ConfirmWorkEmailBody, type ConsumeMagicLinkBody, type Conversation, type ConversationArchive, type ConversationDetail, type ConversationRef, type ConversationsListQuery, type CreateBoardClientOptions, type CreateCompanyBody, type CreateEducationBody, type CreateEmployerJobBody, type CreateExperienceBody, type CreateJobPostingInput, type CreatePipelineStageBody, type CustomStorage, type EditMessageBody, type EmbedJobsQuery, type EmployerApplicant, type EmployerBillingOption, type EmployerCheckout, type EmployerCheckoutBody, type EmployerCompany, type EmployerCompanySearchQuery, type EmployerJob, type EmployerJobSummary, type EmployerJobsListQuery, type EmployerPipeline, type EmployerPipelineQuery, type EmployerPipelineStage, EmploymentType, type FetchOptions, type FindExistingConversationQuery, type ForgotPasswordBody, type HandleAvailability, type JobAlertConfirmation, type JobAlertDeletePreferenceInput, type JobAlertFiltersInput, type JobAlertFrequency, type JobAlertManageQuery, type JobAlertManageResult, type JobAlertManageState, type JobAlertManageTokenInput, type JobAlertPreference, type JobAlertRemoteOption, type JobAlertResendResult, type JobAlertStoredFilters, type JobAlertSubscribeInput, type JobAlertSubscription, type JobAlertUpdatePreferenceInput, JobCardListEnvelope, JobCardSearchEnvelope, type JobPostingBillingCheck, type JobPostingBillingOptions, type JobPostingBillingVerification, type JobPostingLogoResult, type JobPostingPlan, type JobPostingResult, type JobPostingSubscriptionEntitlements, JobsListQuery, JobsSearchBody, JobsSimilarQuery, type LegalEntity, type LegalPageType, ListEnvelope, type Logger, type LoginBody, type LogoutBody, type Message, type ModerationReport, type MoveApplicantStageBody, type NotificationPreference, type OAuthAuthorizationQuery, type OAuthAuthorizationUrl, type OAuthExchangeBody, type OAuthProvider, type Paginator, type PaywallOffer, type PaywallOfferListEnvelope, type PlacesListQuery, type Plan, type PlanListEnvelope, type PlansListQuery, type PublicLegalPage, type PublicPlace, REFRESH_TOKEN_KEY, type ReadReceipt, type RedirectResolution, type RefreshBody, type RegisterBody, RemoteOption, type ReorderPipelineStagesBody, type ReplyBody, type ReportBody, type RequestMagicLinkBody, type ResetPasswordBody, type Resume, type ResumeUploadOptions, SDK_VERSION, SalaryDetailQuery, type SalesLedPlan, type SalesLedPlanListEnvelope, type SaveJobBody, type SavedJob, type SavedJobsListQuery, SearchEnvelope, type SendWorkEmailBody, Seniority, type StartAboutApplicationBody, type StartConversationBody, type StorageMode, type TalentDirectoryEntry, type TalentDirectoryListEnvelope, type TalentDirectoryQuery, type TalentProfile, type TaxonomyGeo, type TaxonomyResolution, type ThreadMessagesQuery, type UnreadCount, type UnsubscribeBody, type UpdateApplicationFactsBody, type UpdateCandidateProfileBody, type UpdateEducationBody, type UpdateEmployerCompanyBody, type UpdateEmployerJobBody, type UpdateExperienceBody, type UpdateLanguagesBody, type UpdateNotificationPreferenceBody, type UpdatePipelineStageBody, type UpdateSkillsBody, type VerifyEmailBody, createBoardClient, isBoardApiError, isBoardPasswordRequired, isColdRule, isConflict, isForbidden, isNotFound, isOwnMessage, isRateLimited, isSafeApplicationUrl, isUnauthorized, isValidationError, lastOwnMessageId, paginate, resolveApplyAction };
package/dist/index.js CHANGED
@@ -36,10 +36,12 @@ __export(src_exports, {
36
36
  isNotFound: () => isNotFound,
37
37
  isOwnMessage: () => isOwnMessage,
38
38
  isRateLimited: () => isRateLimited,
39
+ isSafeApplicationUrl: () => isSafeApplicationUrl,
39
40
  isUnauthorized: () => isUnauthorized,
40
41
  isValidationError: () => isValidationError,
41
42
  lastOwnMessageId: () => lastOwnMessageId,
42
- paginate: () => paginate
43
+ paginate: () => paginate,
44
+ resolveApplyAction: () => resolveApplyAction
43
45
  });
44
46
  module.exports = __toCommonJS(src_exports);
45
47
 
@@ -310,7 +312,7 @@ async function clearSession(storage) {
310
312
  }
311
313
 
312
314
  // src/version.ts
313
- var SDK_VERSION = "1.30.0";
315
+ var SDK_VERSION = "1.31.0-preview.0";
314
316
 
315
317
  // src/client.ts
316
318
  function isRawBody(body) {
@@ -2610,6 +2612,24 @@ function lastOwnMessageId(messages, counterpartyId) {
2610
2612
  return null;
2611
2613
  }
2612
2614
 
2615
+ // src/apply-derive.ts
2616
+ function isSafeApplicationUrl(url) {
2617
+ const cleaned = url.replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, "").replace(/[\t\n\r]/g, "");
2618
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(cleaned)?.[1]?.toLowerCase();
2619
+ if (scheme === void 0) return true;
2620
+ return scheme === "http" || scheme === "https" || scheme === "mailto";
2621
+ }
2622
+ function resolveApplyAction(state) {
2623
+ if (state.applicationUrl && isSafeApplicationUrl(state.applicationUrl)) {
2624
+ return { kind: "external", url: state.applicationUrl };
2625
+ }
2626
+ if (!state.jobSlug) return { kind: "none" };
2627
+ if (!state.viewer) return { kind: "sign-in" };
2628
+ if (!state.viewer.emailVerified) return { kind: "verify-email" };
2629
+ if (state.applied) return { kind: "applied" };
2630
+ return { kind: "native", jobSlug: state.jobSlug };
2631
+ }
2632
+
2613
2633
  // src/index.ts
2614
2634
  function createBoardClient(options) {
2615
2635
  const client = new BoardClient({
package/dist/index.mjs CHANGED
@@ -265,7 +265,7 @@ async function clearSession(storage) {
265
265
  }
266
266
 
267
267
  // src/version.ts
268
- var SDK_VERSION = "1.30.0";
268
+ var SDK_VERSION = "1.31.0-preview.0";
269
269
 
270
270
  // src/client.ts
271
271
  function isRawBody(body) {
@@ -2565,6 +2565,24 @@ function lastOwnMessageId(messages, counterpartyId) {
2565
2565
  return null;
2566
2566
  }
2567
2567
 
2568
+ // src/apply-derive.ts
2569
+ function isSafeApplicationUrl(url) {
2570
+ const cleaned = url.replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, "").replace(/[\t\n\r]/g, "");
2571
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(cleaned)?.[1]?.toLowerCase();
2572
+ if (scheme === void 0) return true;
2573
+ return scheme === "http" || scheme === "https" || scheme === "mailto";
2574
+ }
2575
+ function resolveApplyAction(state) {
2576
+ if (state.applicationUrl && isSafeApplicationUrl(state.applicationUrl)) {
2577
+ return { kind: "external", url: state.applicationUrl };
2578
+ }
2579
+ if (!state.jobSlug) return { kind: "none" };
2580
+ if (!state.viewer) return { kind: "sign-in" };
2581
+ if (!state.viewer.emailVerified) return { kind: "verify-email" };
2582
+ if (state.applied) return { kind: "applied" };
2583
+ return { kind: "native", jobSlug: state.jobSlug };
2584
+ }
2585
+
2568
2586
  // src/index.ts
2569
2587
  function createBoardClient(options) {
2570
2588
  const client = new BoardClient({
@@ -2638,8 +2656,10 @@ export {
2638
2656
  isNotFound,
2639
2657
  isOwnMessage,
2640
2658
  isRateLimited,
2659
+ isSafeApplicationUrl,
2641
2660
  isUnauthorized,
2642
2661
  isValidationError,
2643
2662
  lastOwnMessageId,
2644
- paginate
2663
+ paginate,
2664
+ resolveApplyAction
2645
2665
  };
@@ -3835,4 +3835,4 @@ type JobsSimilarQuery = {
3835
3835
  };
3836
3836
  type JobsSearchBody = Schemas['PublicSearchJobsBody'];
3837
3837
 
3838
- export type { CustomFieldValue as C, EmploymentType as E, JobSort as J, ListEnvelope as L, OfficeLocation as O, PublicJob as P, RemoteOption as R, Seniority as S, PublicJobCard as a, Schemas as b, components as c, JobsListQuery as d, JobCardListEnvelope as e, JobsSearchBody as f, JobCardSearchEnvelope as g, JobsSimilarQuery as h, SearchEnvelope as i, CustomFieldValues as j, EducationRequirement as k, JobCompany as l, RelatedSearch as m, RemotePermit as n, RemoteTimezone as o, StorefrontPagination as p };
3838
+ export type { CustomFieldValues as C, EmploymentType as E, JobSort as J, ListEnvelope as L, OfficeLocation as O, PublicJob as P, RemoteOption as R, Seniority as S, PublicJobCard as a, Schemas as b, components as c, JobsListQuery as d, JobCardListEnvelope as e, JobsSearchBody as f, JobCardSearchEnvelope as g, JobsSimilarQuery as h, SearchEnvelope as i, CustomFieldValue as j, EducationRequirement as k, JobCompany as l, RelatedSearch as m, RemotePermit as n, RemoteTimezone as o, StorefrontPagination as p };
@@ -3835,4 +3835,4 @@ type JobsSimilarQuery = {
3835
3835
  };
3836
3836
  type JobsSearchBody = Schemas['PublicSearchJobsBody'];
3837
3837
 
3838
- export type { CustomFieldValue as C, EmploymentType as E, JobSort as J, ListEnvelope as L, OfficeLocation as O, PublicJob as P, RemoteOption as R, Seniority as S, PublicJobCard as a, Schemas as b, components as c, JobsListQuery as d, JobCardListEnvelope as e, JobsSearchBody as f, JobCardSearchEnvelope as g, JobsSimilarQuery as h, SearchEnvelope as i, CustomFieldValues as j, EducationRequirement as k, JobCompany as l, RelatedSearch as m, RemotePermit as n, RemoteTimezone as o, StorefrontPagination as p };
3838
+ export type { CustomFieldValues as C, EmploymentType as E, JobSort as J, ListEnvelope as L, OfficeLocation as O, PublicJob as P, RemoteOption as R, Seniority as S, PublicJobCard as a, Schemas as b, components as c, JobsListQuery as d, JobCardListEnvelope as e, JobsSearchBody as f, JobCardSearchEnvelope as g, JobsSimilarQuery as h, SearchEnvelope as i, CustomFieldValue as j, EducationRequirement as k, JobCompany as l, RelatedSearch as m, RemotePermit as n, RemoteTimezone as o, StorefrontPagination as p };
@@ -1,18 +1,4 @@
1
- import { b as Schemas, L as ListEnvelope, m as RelatedSearch } from './jobs-lzeoVGY6.js';
2
-
3
- type PublicBoard = Schemas['PublicBoardContext'];
4
- type PublicBoardFeatures = PublicBoard['features'];
5
- type PublicBoardAnalytics = PublicBoard['analytics'];
6
- type PublicBoardTheme = NonNullable<PublicBoard['theme']>;
7
- /**
8
- * An operator-defined custom job-field definition (CAV-294). Board-wide;
9
- * use it to render and localize a job's opaque `customFieldValues` (resolve
10
- * option `key`s → labels, honour field `type` and display order). Shared with
11
- * the Operator API's custom-field surface (one canonical schema).
12
- */
13
- type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
14
- type CustomFieldType = CustomFieldDefinition['type'];
15
- type CustomFieldOption = Schemas['CustomFieldOption'];
1
+ import { b as Schemas, L as ListEnvelope, m as RelatedSearch } from './jobs-Dmz8uexp.js';
16
2
 
17
3
  /** Author shape embedded on posts (no `object` discriminator). */
18
4
  type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
@@ -127,4 +113,4 @@ type SalaryDetailQuery = {
127
113
  locale?: string;
128
114
  };
129
115
 
130
- export type { PublicBoardTheme as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, PublicCompany as D, PublicCompanyDetail as E, SalaryCompany as F, SalaryLocation as G, SalarySkill as H, SalaryTitle as I, SkillLocationSalary as J, SkillLocationsIndex as K, LocationSalaryDetail as L, TitleLocationSalary as M, TitleLocationsIndex as N, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, PublicBlogPostSummary 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, BlogPostsListQuery as j, BlogSimilarQuery as k, BlogSearchBody as l, BlogTagEmbed as m, CompanyMarket as n, CompanyMarketRef as o, CustomFieldDefinition as p, CustomFieldOption as q, CustomFieldType as r, LocationSkillsIndex as s, LocationTitlesIndex as t, PublicBlogAdjacentPosts as u, PublicBlogAuthor as v, PublicBlogPost as w, PublicBlogTag as x, PublicBoardAnalytics as y, PublicBoardFeatures as z };
116
+ export type { SkillLocationSalary as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBlogPostSummary as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanySalary as a, CompaniesListQuery as b, CompanyListEnvelope as c, CompaniesSearchBody as d, CompanyJobsListQuery as e, CompanySimilarQuery as f, CompanyMarketsListQuery as g, SalaryDetailQuery as h, BlogPostsListQuery as i, BlogSimilarQuery as j, BlogSearchBody as k, BlogTagEmbed as l, CompanyMarket as m, CompanyMarketRef as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBlogAdjacentPosts as q, PublicBlogAuthor as r, PublicBlogPost as s, PublicBlogTag as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
@@ -1,18 +1,4 @@
1
- import { b as Schemas, L as ListEnvelope, m as RelatedSearch } from './jobs-lzeoVGY6.mjs';
2
-
3
- type PublicBoard = Schemas['PublicBoardContext'];
4
- type PublicBoardFeatures = PublicBoard['features'];
5
- type PublicBoardAnalytics = PublicBoard['analytics'];
6
- type PublicBoardTheme = NonNullable<PublicBoard['theme']>;
7
- /**
8
- * An operator-defined custom job-field definition (CAV-294). Board-wide;
9
- * use it to render and localize a job's opaque `customFieldValues` (resolve
10
- * option `key`s → labels, honour field `type` and display order). Shared with
11
- * the Operator API's custom-field surface (one canonical schema).
12
- */
13
- type CustomFieldDefinition = Schemas['CustomFieldDefinition'];
14
- type CustomFieldType = CustomFieldDefinition['type'];
15
- type CustomFieldOption = Schemas['CustomFieldOption'];
1
+ import { b as Schemas, L as ListEnvelope, m as RelatedSearch } from './jobs-Dmz8uexp.mjs';
16
2
 
17
3
  /** Author shape embedded on posts (no `object` discriminator). */
18
4
  type BlogAuthorEmbed = Schemas['PublicBlogAuthorEmbed'];
@@ -127,4 +113,4 @@ type SalaryDetailQuery = {
127
113
  locale?: string;
128
114
  };
129
115
 
130
- export type { PublicBoardTheme as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, PublicCompany as D, PublicCompanyDetail as E, SalaryCompany as F, SalaryLocation as G, SalarySkill as H, SalaryTitle as I, SkillLocationSalary as J, SkillLocationsIndex as K, LocationSalaryDetail as L, TitleLocationSalary as M, TitleLocationsIndex as N, PublicBoard as P, SkillSalaryDetail as S, TitleSalaryDetail as T, PublicBlogPostSummary 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, BlogPostsListQuery as j, BlogSimilarQuery as k, BlogSearchBody as l, BlogTagEmbed as m, CompanyMarket as n, CompanyMarketRef as o, CustomFieldDefinition as p, CustomFieldOption as q, CustomFieldType as r, LocationSkillsIndex as s, LocationTitlesIndex as t, PublicBlogAdjacentPosts as u, PublicBlogAuthor as v, PublicBlogPost as w, PublicBlogTag as x, PublicBoardAnalytics as y, PublicBoardFeatures as z };
116
+ export type { SkillLocationSalary as A, BlogAuthorEmbed as B, CompanyCategorySalary as C, SkillLocationsIndex as D, TitleLocationSalary as E, TitleLocationsIndex as F, LocationSalaryDetail as L, PublicBlogPostSummary as P, SkillSalaryDetail as S, TitleSalaryDetail as T, CompanySalary as a, CompaniesListQuery as b, CompanyListEnvelope as c, CompaniesSearchBody as d, CompanyJobsListQuery as e, CompanySimilarQuery as f, CompanyMarketsListQuery as g, SalaryDetailQuery as h, BlogPostsListQuery as i, BlogSimilarQuery as j, BlogSearchBody as k, BlogTagEmbed as l, CompanyMarket as m, CompanyMarketRef as n, LocationSkillsIndex as o, LocationTitlesIndex as p, PublicBlogAdjacentPosts as q, PublicBlogAuthor as r, PublicBlogPost as s, PublicBlogTag as t, PublicCompany as u, PublicCompanyDetail as v, SalaryCompany as w, SalaryLocation as x, SalarySkill as y, SalaryTitle as z };
package/dist/seo.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { P as PublicBoard, a as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-DpH5CxdM.mjs';
2
- import { P as PublicJob } from './jobs-lzeoVGY6.mjs';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, a as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-QXFAyysR.mjs';
2
+ import { P as PublicBoard } from './board-BS8Ax7hz.mjs';
3
+ import { P as PublicJob } from './jobs-Dmz8uexp.mjs';
3
4
 
4
5
  /**
5
6
  * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
@@ -132,6 +133,18 @@ interface BreadcrumbItemInput {
132
133
  declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
133
134
  origin?: string | null;
134
135
  }): JsonLdObject | null;
136
+ /**
137
+ * Home › Jobs › [country › region › city] › primaryCategory › Title.
138
+ * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
139
+ * the category crumb nests under the most-specific place when present
140
+ * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
141
+ * crumb (the job title) carries no `path` — the current page. Mirrors
142
+ * page.tsx:336-367.
143
+ */
144
+ declare function buildJobBreadcrumbs(job: PublicJob): Array<{
145
+ name: string;
146
+ path?: string;
147
+ }>;
135
148
 
136
149
  /**
137
150
  * Framework-neutral `<head>` + structural JSON-LD builders for jobs-listing
@@ -285,4 +298,4 @@ declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdOb
285
298
  /** `Occupation` for one job category at a company (the hosted category page). */
286
299
  declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
287
300
 
288
- export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
301
+ export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildJobBreadcrumbs, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
package/dist/seo.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { P as PublicBoard, a as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, b as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-Cy3MhZov.js';
2
- import { P as PublicJob } from './jobs-lzeoVGY6.js';
1
+ import { P as PublicBlogPostSummary, B as BlogAuthorEmbed, C as CompanyCategorySalary, a as CompanySalary, L as LocationSalaryDetail, S as SkillSalaryDetail, T as TitleSalaryDetail } from './salaries-CrtQBy81.js';
2
+ import { P as PublicBoard } from './board--nLjpneU.js';
3
+ import { P as PublicJob } from './jobs-Dmz8uexp.js';
3
4
 
4
5
  /**
5
6
  * Google for Jobs `JobPosting` structured data on the `@cavuno/board` wire
@@ -132,6 +133,18 @@ interface BreadcrumbItemInput {
132
133
  declare function createBreadcrumbJsonLd(items: BreadcrumbItemInput[], options?: {
133
134
  origin?: string | null;
134
135
  }): JsonLdObject | null;
136
+ /**
137
+ * Home › Jobs › [country › region › city] › primaryCategory › Title.
138
+ * The place crumbs link into the listing routes (`/jobs/locations/:slug`);
139
+ * the category crumb nests under the most-specific place when present
140
+ * (`/jobs/locations/:place/:category`), else `/jobs/:category`. The last
141
+ * crumb (the job title) carries no `path` — the current page. Mirrors
142
+ * page.tsx:336-367.
143
+ */
144
+ declare function buildJobBreadcrumbs(job: PublicJob): Array<{
145
+ name: string;
146
+ path?: string;
147
+ }>;
135
148
 
136
149
  /**
137
150
  * Framework-neutral `<head>` + structural JSON-LD builders for jobs-listing
@@ -285,4 +298,4 @@ declare function companySalaryJsonLd(locale: string, d: CompanySalary): JsonLdOb
285
298
  /** `Occupation` for one job category at a company (the hosted category page). */
286
299
  declare function companyCategorySalaryJsonLd(locale: string, d: CompanyCategorySalary): JsonLdObject | null;
287
300
 
288
- export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
301
+ export { ALL_COUNTRY_CODES, type ArticleJsonLdPost, type BreadcrumbItemInput, type FaqItem, type JsonLdBoard, type JsonLdObject, type ListingHeadOptions, SENIORITY_ORDER, buildJobBreadcrumbs, buildSalaryFaq, companyCategorySalaryJsonLd, companySalaryJsonLd, createAuthorProfileJsonLd, createBlogArticleJsonLd, createBreadcrumbJsonLd, createJobPostingJsonLd, crossAxisSalaryJsonLd, faqJsonLd, formatRange, formatSeniority, formatUsd, itemListJsonLd, listingHead, listingJsonLd, locationSalaryJsonLd, normalizeWebsiteUrl, skillSalaryJsonLd, sortBySeniority, titleSalaryJsonLd };
package/dist/seo.js CHANGED
@@ -22,6 +22,7 @@ var seo_exports = {};
22
22
  __export(seo_exports, {
23
23
  ALL_COUNTRY_CODES: () => ALL_COUNTRY_CODES,
24
24
  SENIORITY_ORDER: () => SENIORITY_ORDER,
25
+ buildJobBreadcrumbs: () => buildJobBreadcrumbs,
25
26
  buildSalaryFaq: () => buildSalaryFaq,
26
27
  companyCategorySalaryJsonLd: () => companyCategorySalaryJsonLd,
27
28
  companySalaryJsonLd: () => companySalaryJsonLd,
@@ -203,6 +204,26 @@ function resolveBreadcrumbHref(href, origin) {
203
204
  function isAbsoluteUrl(href) {
204
205
  return /^https?:\/\//i.test(href);
205
206
  }
207
+ function buildJobBreadcrumbs(job) {
208
+ const crumbs = [
209
+ { name: "Home", path: "/" },
210
+ { name: "Jobs", path: "/jobs" }
211
+ ];
212
+ let lastPlaceSlug = null;
213
+ for (const place of job.placeHierarchy) {
214
+ lastPlaceSlug = place.slug;
215
+ crumbs.push({ name: place.name, path: `/jobs/locations/${place.slug}` });
216
+ }
217
+ const primaryCategory = job.categories[0];
218
+ if (primaryCategory) {
219
+ crumbs.push({
220
+ name: primaryCategory.name,
221
+ path: lastPlaceSlug ? `/jobs/locations/${lastPlaceSlug}/${primaryCategory.slug}` : `/jobs/${primaryCategory.slug}`
222
+ });
223
+ }
224
+ crumbs.push({ name: job.title });
225
+ return crumbs;
226
+ }
206
227
 
207
228
  // src/seo/job-posting.ts
208
229
  var EDUCATION_TO_CREDENTIAL = {
package/dist/seo.mjs CHANGED
@@ -156,6 +156,26 @@ function resolveBreadcrumbHref(href, origin) {
156
156
  function isAbsoluteUrl(href) {
157
157
  return /^https?:\/\//i.test(href);
158
158
  }
159
+ function buildJobBreadcrumbs(job) {
160
+ const crumbs = [
161
+ { name: "Home", path: "/" },
162
+ { name: "Jobs", path: "/jobs" }
163
+ ];
164
+ let lastPlaceSlug = null;
165
+ for (const place of job.placeHierarchy) {
166
+ lastPlaceSlug = place.slug;
167
+ crumbs.push({ name: place.name, path: `/jobs/locations/${place.slug}` });
168
+ }
169
+ const primaryCategory = job.categories[0];
170
+ if (primaryCategory) {
171
+ crumbs.push({
172
+ name: primaryCategory.name,
173
+ path: lastPlaceSlug ? `/jobs/locations/${lastPlaceSlug}/${primaryCategory.slug}` : `/jobs/${primaryCategory.slug}`
174
+ });
175
+ }
176
+ crumbs.push({ name: job.title });
177
+ return crumbs;
178
+ }
159
179
 
160
180
  // src/seo/job-posting.ts
161
181
  var EDUCATION_TO_CREDENTIAL = {
@@ -1056,6 +1076,7 @@ function companyCategorySalaryJsonLd(locale, d) {
1056
1076
  export {
1057
1077
  ALL_COUNTRY_CODES,
1058
1078
  SENIORITY_ORDER,
1079
+ buildJobBreadcrumbs,
1059
1080
  buildSalaryFaq,
1060
1081
  companyCategorySalaryJsonLd,
1061
1082
  companySalaryJsonLd,
package/dist/server.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './jobs-lzeoVGY6.mjs';
3
- import './salaries-DpH5CxdM.mjs';
2
+ import './jobs-Dmz8uexp.mjs';
3
+ import './board-BS8Ax7hz.mjs';
4
+ import './salaries-QXFAyysR.mjs';
4
5
 
5
6
  /**
6
7
  * Session cookie codec — pure (no framework imports, no node imports) so it
package/dist/server.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './jobs-lzeoVGY6.js';
3
- import './salaries-Cy3MhZov.js';
2
+ import './jobs-Dmz8uexp.js';
3
+ import './board--nLjpneU.js';
4
+ import './salaries-CrtQBy81.js';
4
5
 
5
6
  /**
6
7
  * Session cookie codec — pure (no framework imports, no node imports) so it
@@ -1,6 +1,7 @@
1
1
  import { BoardSdk } from './index.mjs';
2
- import './jobs-lzeoVGY6.mjs';
3
- import './salaries-DpH5CxdM.mjs';
2
+ import './jobs-Dmz8uexp.mjs';
3
+ import './board-BS8Ax7hz.mjs';
4
+ import './salaries-QXFAyysR.mjs';
4
5
 
5
6
  /**
6
7
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/dist/sitemap.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BoardSdk } from './index.js';
2
- import './jobs-lzeoVGY6.js';
3
- import './salaries-Cy3MhZov.js';
2
+ import './jobs-Dmz8uexp.js';
3
+ import './board--nLjpneU.js';
4
+ import './salaries-CrtQBy81.js';
4
5
 
5
6
  /**
6
7
  * Sitemap primitives — the pure XML + bucket-filename logic behind a board
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "1.30.0",
3
+ "version": "1.31.0-preview.0",
4
4
  "description": "Typed isomorphic client for the Cavuno Board API",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.30.0",
2
+ "version": "1.31.0-preview.0",
3
3
  "skills": [
4
4
  {
5
5
  "name": "cavuno-board-account",