@cavuno/board 2.0.0 → 2.0.2

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 (84) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/CONTRIBUTING.md +25 -0
  3. package/LICENSE +21 -0
  4. package/README.md +12 -7
  5. package/SECURITY.md +28 -0
  6. package/TRADEMARKS.md +16 -0
  7. package/dist/_spec-sW85fuvT.d.mts +2731 -0
  8. package/dist/_spec-sW85fuvT.d.ts +2731 -0
  9. package/dist/bin.mjs +16 -348
  10. package/dist/{board-B8tJGX4i.d.ts → board-DKXyxwNN.d.ts} +2 -2
  11. package/dist/{board-DmRuCA8m.d.mts → board-QFeHT4UN.d.mts} +2 -2
  12. package/dist/doctor.d.mts +6 -19
  13. package/dist/doctor.d.ts +6 -19
  14. package/dist/doctor.js +16 -344
  15. package/dist/doctor.mjs +15 -343
  16. package/dist/filters.d.mts +5 -5
  17. package/dist/filters.d.ts +5 -5
  18. package/dist/format.d.mts +17 -19
  19. package/dist/format.d.ts +17 -19
  20. package/dist/go.d.mts +2 -2
  21. package/dist/go.d.ts +2 -2
  22. package/dist/go.js +1 -1
  23. package/dist/go.mjs +1 -1
  24. package/dist/index.d.mts +16 -18
  25. package/dist/index.d.ts +16 -18
  26. package/dist/index.js +39 -28
  27. package/dist/index.mjs +39 -28
  28. package/dist/{jobs-BEYJY97F.d.ts → jobs-CuRzTDb1.d.mts} +15 -13
  29. package/dist/{jobs-DJiISpqX.d.mts → jobs-DTnCZGtb.d.ts} +15 -13
  30. package/dist/paths.d.mts +6 -6
  31. package/dist/paths.d.ts +6 -6
  32. package/dist/paths.js +1 -1
  33. package/dist/paths.mjs +1 -1
  34. package/dist/roles-vY0AXhoc.d.mts +3 -3
  35. package/dist/roles-vY0AXhoc.d.ts +3 -3
  36. package/dist/route-contract.d.mts +16 -16
  37. package/dist/route-contract.d.ts +16 -16
  38. package/dist/route-contract.js +1 -1
  39. package/dist/route-contract.mjs +1 -1
  40. package/dist/{salaries-D6q7h1J6.d.ts → salaries-BOpR51Ny.d.mts} +3 -3
  41. package/dist/{salaries-B_Xb5k2s.d.mts → salaries-QoNpzRCT.d.ts} +3 -3
  42. package/dist/{search-CnOIZEuc.d.ts → search-B5ROY6PK.d.ts} +2 -2
  43. package/dist/{search-uC_ijbdu.d.mts → search-f93nrSg3.d.mts} +2 -2
  44. package/dist/seo.d.mts +17 -18
  45. package/dist/seo.d.ts +17 -18
  46. package/dist/server.d.mts +14 -32
  47. package/dist/server.d.ts +14 -32
  48. package/dist/sitemap.d.mts +7 -7
  49. package/dist/sitemap.d.ts +7 -7
  50. package/dist/sitemap.js +4 -2
  51. package/dist/sitemap.mjs +4 -2
  52. package/dist/skills.d.mts +1 -1
  53. package/dist/skills.d.ts +1 -1
  54. package/dist/skills.js +1 -1
  55. package/dist/suggest.d.mts +2 -2
  56. package/dist/suggest.d.ts +2 -2
  57. package/dist/theme.d.mts +10 -13
  58. package/dist/theme.d.ts +10 -13
  59. package/dist/theme.js +1 -1
  60. package/dist/theme.mjs +1 -1
  61. package/dist/{ui-copy-CKfFTtLk.d.mts → ui-copy-CL-VN1xb.d.mts} +2 -3
  62. package/dist/{ui-copy-CKfFTtLk.d.ts → ui-copy-CL-VN1xb.d.ts} +2 -3
  63. package/dist/well-known.d.mts +3 -3
  64. package/dist/well-known.d.ts +3 -3
  65. package/dist/well-known.js +1 -1
  66. package/dist/well-known.mjs +1 -1
  67. package/package.json +46 -38
  68. package/skills/cavuno-board-client/SKILL.md +1 -2
  69. package/skills/cavuno-board-filters/SKILL.md +2 -2
  70. package/skills/cavuno-board-format/SKILL.md +1 -1
  71. package/skills/cavuno-board-i18n/SKILL.md +3 -4
  72. package/skills/cavuno-board-job-posting/SKILL.md +1 -1
  73. package/skills/cavuno-board-messaging/SKILL.md +2 -3
  74. package/skills/cavuno-board-paywall/SKILL.md +1 -1
  75. package/skills/cavuno-board-salaries/SKILL.md +1 -1
  76. package/skills/cavuno-board-seo/SKILL.md +4 -6
  77. package/skills/cavuno-board-server/SKILL.md +1 -1
  78. package/skills/cavuno-board-setup/SKILL.md +2 -1
  79. package/skills/cavuno-board-sitemap/SKILL.md +1 -1
  80. package/skills/cavuno-board-smoke-test/SKILL.md +4 -13
  81. package/skills/flavors/tanstack-start/SKILL.md +1 -2
  82. package/skills/manifest.json +1 -1
  83. package/dist/_spec-C7vqY_b3.d.mts +0 -5202
  84. package/dist/_spec-C7vqY_b3.d.ts +0 -5202
package/dist/doctor.mjs CHANGED
@@ -392,86 +392,18 @@ async function runReadProbes(fetchImpl, frontendUrl) {
392
392
  ];
393
393
  }
394
394
 
395
- // src/doctor/sandbox.ts
396
- var SANDBOX_GATE = record("sandbox.persona-gate", 1);
397
- var EXPECTED_PERSONA_COUNT = 8;
398
- function skipSandboxPersonaGate(reason) {
399
- return SANDBOX_GATE("skip", reason);
400
- }
401
- async function checkSandboxPersonaGate(fetchImpl, env, boardContext) {
402
- if (boardContext === null) {
403
- return SANDBOX_GATE(
404
- "skip",
405
- "board did not resolve \u2014 fix static.board first"
406
- );
407
- }
408
- const url = `${apiBase(env.apiUrl)}/v1/boards/${encodeURIComponent(env.boardKey)}/sandbox/personas`;
409
- const result = await probe(fetchImpl, url);
410
- if (boardContext.sandbox !== true) {
411
- return result.status === 404 ? SANDBOX_GATE(
412
- "pass",
413
- "sandbox persona endpoint refuses (404) on a non-sandbox board"
414
- ) : SANDBOX_GATE(
415
- "fail",
416
- `sandbox persona endpoint is reachable on a NON-sandbox board (HTTP ${result.status}) \u2014 the capability gate is not holding`
417
- );
418
- }
419
- if (!result.ok) {
420
- return SANDBOX_GATE(
421
- "fail",
422
- `sandbox persona roster did not resolve (HTTP ${result.status}) \u2014 the persona seed may have failed`
423
- );
424
- }
425
- let personas;
426
- let password;
427
- try {
428
- const parsed = JSON.parse(result.body);
429
- personas = parsed.personas;
430
- password = parsed.password;
431
- } catch {
432
- return SANDBOX_GATE(
433
- "fail",
434
- "sandbox persona endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
435
- );
436
- }
437
- if (!Array.isArray(personas) || personas.length !== EXPECTED_PERSONA_COUNT) {
438
- return SANDBOX_GATE(
439
- "fail",
440
- `expected ${EXPECTED_PERSONA_COUNT} personas, got ${Array.isArray(personas) ? personas.length : "a non-array"} \u2014 the persona seed is incomplete`
441
- );
442
- }
443
- const unseeded = personas.filter((persona) => persona.seeded !== true);
444
- if (unseeded.length > 0) {
445
- const ids = unseeded.map((persona) => typeof persona.id === "string" ? persona.id : "?").join(", ");
446
- return SANDBOX_GATE(
447
- "fail",
448
- `${unseeded.length} of ${EXPECTED_PERSONA_COUNT} personas are not seeded on the board (${ids}) \u2014 the persona seed failed or was purged; run POST /v1/boards/{key}/sandbox/reseed to restore the roster`
449
- );
450
- }
451
- if (typeof password !== "string" || password.length === 0) {
452
- return SANDBOX_GATE(
453
- "fail",
454
- "roster present but the published password is missing"
455
- );
456
- }
457
- return SANDBOX_GATE(
458
- "pass",
459
- `sandbox roster complete and seeded (${EXPECTED_PERSONA_COUNT} personas)`
460
- );
461
- }
462
-
463
395
  // src/doctor/theme.ts
464
396
  import { createHash } from "crypto";
465
397
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
466
398
  import { join as join2 } from "path";
467
399
  var THEME = record("static.theme", 1);
468
- function checkThemeFreshness(projectRoot, context) {
400
+ function checkThemeFreshness(projectRoot) {
469
401
  const tokensPath = join2(projectRoot, "src/tokens.css");
470
402
  if (!existsSync2(tokensPath)) {
471
403
  return [
472
404
  THEME(
473
405
  "skip",
474
- "board is not tokens-migrated (ADR-0065) \u2014 no src/tokens.css"
406
+ "no src/tokens.css \u2014 local theme freshness check not applicable"
475
407
  )
476
408
  ];
477
409
  }
@@ -488,234 +420,11 @@ function checkThemeFreshness(projectRoot, context) {
488
420
  )
489
421
  ];
490
422
  }
491
- if (!context) {
492
- return [
493
- THEME(
494
- "skip",
495
- "local derivations fresh; platform snapshot unverified \u2014 board context unavailable"
496
- )
497
- ];
498
- }
499
- if (context.themeSnapshotHash !== tokensHash) {
500
- return [
501
- THEME(
502
- "fail",
503
- `platform theme snapshot is ${context.themeSnapshotHash ? "stale" : "missing"} \u2014 emails render ${context.themeSnapshotHash ? "an old" : "the legacy"} theme; sync it: \`npm run gen:theme -- --payload | npx convex run boards/themeSnapshot:sync\``
504
- )
505
- ];
506
- }
507
423
  return [
508
- THEME(
509
- "pass",
510
- `tokens.css \u21C4 resolved module \u21C4 platform snapshot (${tokensHash.slice(0, 12)}\u2026)`
511
- )
424
+ THEME("pass", `tokens.css \u21C4 resolved module (${tokensHash.slice(0, 12)}\u2026)`)
512
425
  ];
513
426
  }
514
427
 
515
- // src/doctor/writes.ts
516
- var WRITE = {
517
- board: record("write.board", 3),
518
- register: record("write.register", 3),
519
- login: record("write.login", 3),
520
- email: record("write.email", 3),
521
- apply: record("write.apply", 3),
522
- alert: record("write.alert", 3)
523
- };
524
- var DEPENDENT_CHECKS = [
525
- WRITE.register,
526
- WRITE.login,
527
- WRITE.email,
528
- WRITE.apply,
529
- WRITE.alert
530
- ];
531
- function skipWriteProbes(reason) {
532
- return Object.values(WRITE).map((make) => make("skip", reason));
533
- }
534
- var FETCH_TIMEOUT_MS2 = 1e4;
535
- var RESEND_API_BASE = "https://api.resend.com";
536
- async function request(fetchImpl, url, init) {
537
- try {
538
- const response = await fetchImpl(url, {
539
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2),
540
- ...init
541
- });
542
- let json = null;
543
- try {
544
- json = await response.json();
545
- } catch {
546
- json = null;
547
- }
548
- return { ok: response.ok, status: response.status, json };
549
- } catch (error) {
550
- return {
551
- ok: false,
552
- status: 0,
553
- json: { error: error instanceof Error ? error.message : String(error) }
554
- };
555
- }
556
- }
557
- function post(fetchImpl, url, body, bearer) {
558
- return request(fetchImpl, url, {
559
- method: "POST",
560
- headers: {
561
- "content-type": "application/json",
562
- accept: "application/json",
563
- ...bearer ? { authorization: `Bearer ${bearer}` } : {}
564
- },
565
- body: JSON.stringify(body)
566
- });
567
- }
568
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
569
- async function observeVerificationEmail(fetchImpl, apiKey, recipient, pollMs, timeoutMs) {
570
- const deadline = Date.now() + timeoutMs;
571
- const subjectMarker = `[To: ${recipient}]`;
572
- do {
573
- const list = await request(
574
- fetchImpl,
575
- `${RESEND_API_BASE}/emails?limit=20`,
576
- {
577
- headers: { authorization: `Bearer ${apiKey}` }
578
- }
579
- );
580
- if (!list.ok) {
581
- return WRITE.email(
582
- "fail",
583
- `Resend list returned HTTP ${list.status} \u2014 wrong RESEND_API_KEY?`
584
- );
585
- }
586
- const items = list.json?.data ?? [];
587
- const match = items.find(
588
- (item) => item.subject?.includes(subjectMarker) || item.to?.includes(recipient)
589
- );
590
- if (match) {
591
- return WRITE.email(
592
- "pass",
593
- `verification send observed in Resend for ${recipient}`
594
- );
595
- }
596
- await sleep(pollMs);
597
- } while (Date.now() < deadline);
598
- return WRITE.email(
599
- "fail",
600
- `no verification send for ${recipient} appeared in Resend within ${timeoutMs}ms`
601
- );
602
- }
603
- async function runWriteProbes(options) {
604
- const { fetchImpl } = options;
605
- const base = `${apiBase(options.env.apiUrl)}/v1/boards/${encodeURIComponent(options.env.boardKey)}`;
606
- const nonce = options.nonce ?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
607
- const email = `doctor+${nonce}@cavuno.com`;
608
- const password = `doctor-probe-${nonce}-A1!`;
609
- let context = options.boardContext ?? null;
610
- if (context === null) {
611
- const r = await request(fetchImpl, base);
612
- if (!r.ok) {
613
- return [
614
- WRITE.board("fail", `board context did not resolve (HTTP ${r.status})`),
615
- ...DEPENDENT_CHECKS.map(
616
- (make) => make("skip", "not run \u2014 the write gate failed (see write.board)")
617
- )
618
- ];
619
- }
620
- context = r.json ?? {};
621
- }
622
- if (context.sandbox !== true) {
623
- return [
624
- WRITE.board(
625
- "fail",
626
- "refusing write probes: this board is not the platform sandbox (`sandbox` is not true) \u2014 point PUBLIC_CAVUNO_BOARD at the sandbox pk_"
627
- ),
628
- ...DEPENDENT_CHECKS.map(
629
- (make) => make("skip", "not run \u2014 the write gate failed (see write.board)")
630
- )
631
- ];
632
- }
633
- const results = [
634
- WRITE.board("pass", "board is the platform sandbox")
635
- ];
636
- const registered = await post(fetchImpl, `${base}/auth/register`, {
637
- role: "candidate",
638
- method: "emailpass",
639
- email,
640
- password,
641
- displayName: "Doctor Probe"
642
- });
643
- const sessionOk = (r) => r.ok && typeof r.json?.accessToken === "string";
644
- results.push(
645
- sessionOk(registered) ? WRITE.register("pass", `candidate registered (${email})`) : WRITE.register(
646
- "fail",
647
- `register returned HTTP ${registered.status}` + (registered.status === 429 ? " \u2014 rate-limited: register allows 5 signups / 15 min per IP; wait before rerunning" : "")
648
- )
649
- );
650
- let accessToken = null;
651
- if (sessionOk(registered)) {
652
- const login = await post(fetchImpl, `${base}/auth/login`, {
653
- email,
654
- password
655
- });
656
- if (sessionOk(login)) {
657
- accessToken = login.json.accessToken;
658
- results.push(WRITE.login("pass", "emailpass login returns a session"));
659
- } else {
660
- results.push(WRITE.login("fail", `login returned HTTP ${login.status}`));
661
- }
662
- } else {
663
- results.push(WRITE.login("skip", "not run \u2014 register failed"));
664
- }
665
- if (!sessionOk(registered)) {
666
- results.push(WRITE.email("skip", "not run \u2014 register failed"));
667
- } else if (!options.resendApiKey) {
668
- results.push(
669
- WRITE.email(
670
- "skip",
671
- "RESEND_API_KEY not set \u2014 the verification send was NOT verified (platform-operator check)"
672
- )
673
- );
674
- } else {
675
- results.push(
676
- await observeVerificationEmail(
677
- fetchImpl,
678
- options.resendApiKey,
679
- email,
680
- options.emailPollMs ?? 2e3,
681
- options.emailTimeoutMs ?? 3e4
682
- )
683
- );
684
- }
685
- if (!accessToken) {
686
- results.push(WRITE.apply("skip", "not run \u2014 no session (see above)"));
687
- } else {
688
- const listing = await request(fetchImpl, `${base}/jobs?limit=1`);
689
- const card = listing.json?.data?.[0];
690
- if (!listing.ok || !card?.slug) {
691
- results.push(
692
- WRITE.apply(
693
- "fail",
694
- listing.ok ? "the board has no jobs to apply to \u2014 is the sandbox seeded?" : `jobs listing returned HTTP ${listing.status}`
695
- )
696
- );
697
- } else {
698
- const applied = await post(
699
- fetchImpl,
700
- `${base}/jobs/${encodeURIComponent(card.slug)}/apply`,
701
- {},
702
- accessToken
703
- );
704
- results.push(
705
- applied.ok && typeof applied.json?.id === "string" ? WRITE.apply("pass", `applied to ${card.slug}`) : WRITE.apply("fail", `apply returned HTTP ${applied.status}`)
706
- );
707
- }
708
- }
709
- const alert = await post(fetchImpl, `${base}/job-alerts`, {
710
- email,
711
- consent: true
712
- });
713
- results.push(
714
- alert.ok ? WRITE.alert("pass", "job-alert subscription accepted") : WRITE.alert("fail", `job-alerts returned HTTP ${alert.status}`)
715
- );
716
- return results;
717
- }
718
-
719
428
  // src/doctor/run.ts
720
429
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
721
430
  import { join as join3 } from "path";
@@ -752,31 +461,21 @@ async function checkBoardResolves(fetchImpl, env) {
752
461
  `${apiBase(env.apiUrl)}/v1/boards/${encodeURIComponent(env.boardKey)}`
753
462
  );
754
463
  if (!result.ok) {
755
- return {
756
- result: STATIC_BOARD(
757
- "fail",
758
- `board did not resolve for this key (HTTP ${result.status}) \u2014 revoked or wrong key?`
759
- ),
760
- context: null
761
- };
464
+ return STATIC_BOARD(
465
+ "fail",
466
+ `board did not resolve for this key (HTTP ${result.status}) \u2014 revoked or wrong key?`
467
+ );
762
468
  }
763
- let parsed = null;
764
469
  try {
765
- parsed = JSON.parse(result.body);
470
+ const parsed = JSON.parse(result.body);
766
471
  if (typeof parsed !== "object" || parsed === null) throw new Error("shape");
767
472
  } catch {
768
- return {
769
- result: STATIC_BOARD(
770
- "fail",
771
- "board endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
772
- ),
773
- context: null
774
- };
473
+ return STATIC_BOARD(
474
+ "fail",
475
+ "board endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
476
+ );
775
477
  }
776
- return {
777
- result: STATIC_BOARD("pass", "publishable key resolves the board"),
778
- context: parsed
779
- };
478
+ return STATIC_BOARD("pass", "publishable key resolves the board");
780
479
  }
781
480
  var SKILL_ROOTS = [
782
481
  ".claude/skills",
@@ -839,46 +538,19 @@ async function runDoctor(options) {
839
538
  } else {
840
539
  results.push(STATIC_API("skip", "PUBLIC_CAVUNO_API_URL not set"));
841
540
  }
842
- let boardContext = null;
843
541
  if (envOk) {
844
- const resolved = await checkBoardResolves(fetchImpl, env);
845
- boardContext = resolved.context;
846
- results.push(resolved.result);
542
+ results.push(await checkBoardResolves(fetchImpl, env));
847
543
  } else {
848
544
  results.push(STATIC_BOARD("skip", "env checks failed \u2014 fix them first"));
849
545
  }
850
546
  results.push(checkSkillsFreshness(options.projectRoot ?? process.cwd()));
851
- results.push(
852
- ...checkThemeFreshness(options.projectRoot ?? process.cwd(), boardContext)
853
- );
547
+ results.push(...checkThemeFreshness(options.projectRoot ?? process.cwd()));
854
548
  results.push(
855
549
  ...checkCookieCodecConformance(options.projectRoot ?? process.cwd())
856
550
  );
857
- results.push(
858
- envOk ? await checkSandboxPersonaGate(fetchImpl, env, boardContext) : skipSandboxPersonaGate("env checks failed \u2014 fix them first")
859
- );
860
551
  results.push(
861
552
  ...options.frontendUrl ? await runReadProbes(fetchImpl, options.frontendUrl) : skipReadProbes("no --frontend <url> given")
862
553
  );
863
- if (!options.sandbox) {
864
- results.push(
865
- ...skipWriteProbes(
866
- "write probes not enabled \u2014 run with --sandbox against the platform sandbox"
867
- )
868
- );
869
- } else if (!envOk) {
870
- results.push(...skipWriteProbes("env checks failed \u2014 fix them first"));
871
- } else {
872
- results.push(
873
- ...await runWriteProbes({
874
- env,
875
- fetchImpl,
876
- resendApiKey: options.resendApiKey,
877
- nonce: options.writeProbeNonce,
878
- boardContext
879
- })
880
- );
881
- }
882
554
  return { results, summary: summarize(results) };
883
555
  }
884
556
  export {
@@ -1,6 +1,6 @@
1
- import { B as BoardLabelOverrides } from './ui-copy-CKfFTtLk.mjs';
2
- import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-DJiISpqX.mjs';
3
- import './_spec-C7vqY_b3.mjs';
1
+ import { B as BoardLabelOverrides } from './ui-copy-CL-VN1xb.mjs';
2
+ import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-CuRzTDb1.mjs';
3
+ import './_spec-sW85fuvT.mjs';
4
4
 
5
5
  declare const REMOTE_OPTIONS: readonly RemoteOption[];
6
6
  /**
@@ -23,7 +23,7 @@ declare const DEFAULT_SORT: JobSort;
23
23
  declare function seniorityLabels(locale: string, labels?: BoardLabelOverrides): Record<Seniority, string>;
24
24
  /**
25
25
  * Sort-dropdown labels in the board language, resolved from the copy
26
- * catalog (`uiCopy(locale).jobCard`, ADR-0059) ⊕ stored operator overrides
26
+ * catalog (`uiCopy(locale).jobCard`) ⊕ stored operator overrides
27
27
  * (`jobCardLabels.aiRankedLabel` / `sortNewestLabel` / `sortSalaryHighLabel`)
28
28
  * when the `labels` bag is passed.
29
29
  */
@@ -40,7 +40,7 @@ interface ListingFilters {
40
40
  * wire as `companySlug` (`jobs.list` query / `jobs.search` filters).
41
41
  */
42
42
  company?: string[];
43
- /** Result ordering (ADR-0048); absent ⇒ `relevance`. */
43
+ /** Result ordering; absent ⇒ `relevance`. */
44
44
  sort?: JobSort;
45
45
  }
46
46
  /**
package/dist/filters.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { B as BoardLabelOverrides } from './ui-copy-CKfFTtLk.js';
2
- import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-BEYJY97F.js';
3
- import './_spec-C7vqY_b3.js';
1
+ import { B as BoardLabelOverrides } from './ui-copy-CL-VN1xb.js';
2
+ import { J as JobSort, E as EmploymentType, R as RemoteOption, S as Seniority } from './jobs-DTnCZGtb.js';
3
+ import './_spec-sW85fuvT.js';
4
4
 
5
5
  declare const REMOTE_OPTIONS: readonly RemoteOption[];
6
6
  /**
@@ -23,7 +23,7 @@ declare const DEFAULT_SORT: JobSort;
23
23
  declare function seniorityLabels(locale: string, labels?: BoardLabelOverrides): Record<Seniority, string>;
24
24
  /**
25
25
  * Sort-dropdown labels in the board language, resolved from the copy
26
- * catalog (`uiCopy(locale).jobCard`, ADR-0059) ⊕ stored operator overrides
26
+ * catalog (`uiCopy(locale).jobCard`) ⊕ stored operator overrides
27
27
  * (`jobCardLabels.aiRankedLabel` / `sortNewestLabel` / `sortSalaryHighLabel`)
28
28
  * when the `labels` bag is passed.
29
29
  */
@@ -40,7 +40,7 @@ interface ListingFilters {
40
40
  * wire as `companySlug` (`jobs.list` query / `jobs.search` filters).
41
41
  */
42
42
  company?: string[];
43
- /** Result ordering (ADR-0048); absent ⇒ `relevance`. */
43
+ /** Result ordering; absent ⇒ `relevance`. */
44
44
  sort?: JobSort;
45
45
  }
46
46
  /**
package/dist/format.d.mts CHANGED
@@ -1,13 +1,13 @@
1
- import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-DJiISpqX.mjs';
2
- import { B as BoardLabelOverrides } from './ui-copy-CKfFTtLk.mjs';
3
- export { A as AlertsCopy, a as ApplyCopy, b as BlogCopy, c as BreadcrumbsCopy, C as CopyLinkCopy, E as EntityCopy, F as FooterCopy, J as JobCardCopy, d as JobDetailCopy, e as JobSearchCopy, N as NavCopy, P as PUBLIC_LABEL_GROUPS, f as PaginationCopy, S as SalaryCopy, U as UiCopy, u as uiCopy } from './ui-copy-CKfFTtLk.mjs';
4
- import { C as CustomFieldDefinition } from './board-DmRuCA8m.mjs';
5
- import './_spec-C7vqY_b3.mjs';
1
+ import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-CuRzTDb1.mjs';
2
+ import { B as BoardLabelOverrides } from './ui-copy-CL-VN1xb.mjs';
3
+ export { A as AlertsCopy, a as ApplyCopy, b as BlogCopy, c as BreadcrumbsCopy, C as CopyLinkCopy, E as EntityCopy, F as FooterCopy, J as JobCardCopy, d as JobDetailCopy, e as JobSearchCopy, N as NavCopy, P as PUBLIC_LABEL_GROUPS, f as PaginationCopy, S as SalaryCopy, U as UiCopy, u as uiCopy } from './ui-copy-CL-VN1xb.mjs';
4
+ import { C as CustomFieldDefinition } from './board-QFeHT4UN.mjs';
5
+ import './_spec-sW85fuvT.mjs';
6
6
 
7
7
  /**
8
8
  * Date display helpers in the board language (required leading parameter,
9
- * ADR-0057) — transcribed from the hosted board's `date-labels.ts` and
10
- * golden-tested against it in-monorepo.
9
+ * ) — transcribed from the hosted board's `date-labels.ts` and
10
+ * tested against the hosted behavior.
11
11
  *
12
12
  * Job cards and the job-detail header render the RELATIVE form
13
13
  * (`formatPublishedRelativeDate` — "5d ago"); the absolute medium date
@@ -28,7 +28,7 @@ declare function formatDate(locale: string, value: string | number | null): stri
28
28
  declare function formatPublishedRelativeDate(locale: string, value: string | number | null, referenceNowMs?: number): string | null;
29
29
  /**
30
30
  * Month-year label, e.g. "Jun 2023" — transcribed from the hosted board's
31
- * `formatMonthYear` (golden-tested in-monorepo). The `T00:00:00` suffix
31
+ * `formatMonthYear`. The `T00:00:00` suffix
32
32
  * prevents timezone-related off-by-one-month issues on date-only strings.
33
33
  */
34
34
  declare function formatMonthYear(locale: string, dateStr: string): string;
@@ -38,7 +38,7 @@ declare function formatMonthYear(locale: string, dateStr: string): string;
38
38
  * `PublicJobCard` shape a list card renders — computing the card's
39
39
  * pre-resolved `locationLabel`/`remoteLocationLabel` from the full job's
40
40
  * fields. Board language is required because the computed location label is
41
- * display text (ADR-0057).
41
+ * display text.
42
42
  */
43
43
  declare function fullJobToCard(locale: string, job: PublicJob): PublicJobCard;
44
44
 
@@ -59,7 +59,7 @@ declare function fieldLabel(locale: string, value: string | null, labels?: Board
59
59
 
60
60
  /**
61
61
  * Location display labels for job cards and detail pages, in the board
62
- * language (required leading parameter, ADR-0057). The wrapper words
62
+ * language. The wrapper words
63
63
  * ("Remote", "(hybrid)", "Worldwide") follow the hosted board's current
64
64
  * English-only rendering; place names arrive already board-language from the
65
65
  * wire (the API serves canonical, localized labels).
@@ -84,8 +84,7 @@ declare function cardLocationLabel(locale: string, job: Pick<PublicJobCard, 'rem
84
84
  * `<title>`/`<description>` sentence FRAMES, keyed by the board language
85
85
  * (`board.context().language`), NOT by any visitor locale.
86
86
  *
87
- * Transcribed from the hosted board's `salary-lexicon.ts` (CAV-352 /
88
- * ADR-0012) and golden-tested against it in-monorepo (ADR-0057): the two
87
+ * Transcribed from the hosted board's `salary-lexicon.ts` and tested against it : the two
89
88
  * copies cannot drift silently. The `de` strings are native-reviewed.
90
89
  * Unseeded locales fall back to the English source WORDS while number and
91
90
  * currency formatting stays locale-correct.
@@ -229,7 +228,7 @@ interface SalaryTimeframeOverrides {
229
228
  }
230
229
  /**
231
230
  * Format a per-job salary range in the BOARD language
232
- * (`board.context().language` — required, never defaulted; see ADR-0057).
231
+ * (`board.context().language` — required, never defaulted; see ).
233
232
  * The fixed words (timeframe, "From"/"Up to") come from
234
233
  * `getSalaryLexicon(language)` with precedence owner-override > lexicon >
235
234
  * English source. Currency placement is gated: `en` keeps the legacy manual
@@ -251,7 +250,7 @@ declare function companyIntro(summary: string | null, description: string | null
251
250
  * permit taxonomy (`GET /v1/taxonomies/remote-permits`), published so a
252
251
  * picker on any surface offers exactly the set the API accepts. Mirrors the
253
252
  * platform's canonical `COUNTRIES` dataset (`world-countries` minus `KP`,
254
- * plus `XK`/Kosovo); an in-monorepo parity test asserts the mirror cannot
253
+ * plus `XK`/Kosovo); an parity test asserts the mirror cannot
255
254
  * drift. Codes only — display names localize at render via
256
255
  * `countryOptions(language)`.
257
256
  */
@@ -263,7 +262,7 @@ interface CountryOption {
263
262
  }
264
263
  /**
265
264
  * The complete country option list, display-named in the BOARD language
266
- * (required leading parameter, ADR-0057) and sorted by that language's
265
+ * and sorted by that language's
267
266
  * collation — the shape a country picker renders. Falls back to the bare
268
267
  * code when the runtime cannot resolve the language or name a region.
269
268
  */
@@ -271,15 +270,14 @@ declare function countryOptions(language: string): CountryOption[];
271
270
 
272
271
  /**
273
272
  * Resolve a job's opaque `customFieldValues` into ordered, display-ready
274
- * entries for the "Additional details" section — the client-side twin of the
275
- * hosted `resolveCustomFieldDisplay` (apps/web/lib/jobs/job-form-config/
276
- * custom-field-display.ts). Pure. Iterates the *definitions* (from board
273
+ * entries for the "Additional details" section, matching the hosted board's
274
+ * display behavior. Pure. Iterates the *definitions* (from board
277
275
  * context) in config order, so display order is operator-controlled, orphan
278
276
  * values (deleted definitions) are never inspected, and empty values drop per
279
277
  * field. Select values resolve their stored option KEY to the current label
280
278
  * (rename-safe); an option with no current match is dropped. Booleans stay raw
281
279
  * (a discriminated `kind`) — the render layer authors the "Yes"/"No" chrome
282
- * (English; localized copy is the use-intl follow-up).
280
+ * (English; localized copy is the use-intl future release).
283
281
  */
284
282
  type CustomFieldDisplayEntry = {
285
283
  key: string;
package/dist/format.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-BEYJY97F.js';
2
- import { B as BoardLabelOverrides } from './ui-copy-CKfFTtLk.js';
3
- export { A as AlertsCopy, a as ApplyCopy, b as BlogCopy, c as BreadcrumbsCopy, C as CopyLinkCopy, E as EntityCopy, F as FooterCopy, J as JobCardCopy, d as JobDetailCopy, e as JobSearchCopy, N as NavCopy, P as PUBLIC_LABEL_GROUPS, f as PaginationCopy, S as SalaryCopy, U as UiCopy, u as uiCopy } from './ui-copy-CKfFTtLk.js';
4
- import { C as CustomFieldDefinition } from './board-B8tJGX4i.js';
5
- import './_spec-C7vqY_b3.js';
1
+ import { P as PublicJob, a as PublicJobCard, C as CustomFieldValues } from './jobs-DTnCZGtb.js';
2
+ import { B as BoardLabelOverrides } from './ui-copy-CL-VN1xb.js';
3
+ export { A as AlertsCopy, a as ApplyCopy, b as BlogCopy, c as BreadcrumbsCopy, C as CopyLinkCopy, E as EntityCopy, F as FooterCopy, J as JobCardCopy, d as JobDetailCopy, e as JobSearchCopy, N as NavCopy, P as PUBLIC_LABEL_GROUPS, f as PaginationCopy, S as SalaryCopy, U as UiCopy, u as uiCopy } from './ui-copy-CL-VN1xb.js';
4
+ import { C as CustomFieldDefinition } from './board-DKXyxwNN.js';
5
+ import './_spec-sW85fuvT.js';
6
6
 
7
7
  /**
8
8
  * Date display helpers in the board language (required leading parameter,
9
- * ADR-0057) — transcribed from the hosted board's `date-labels.ts` and
10
- * golden-tested against it in-monorepo.
9
+ * ) — transcribed from the hosted board's `date-labels.ts` and
10
+ * tested against the hosted behavior.
11
11
  *
12
12
  * Job cards and the job-detail header render the RELATIVE form
13
13
  * (`formatPublishedRelativeDate` — "5d ago"); the absolute medium date
@@ -28,7 +28,7 @@ declare function formatDate(locale: string, value: string | number | null): stri
28
28
  declare function formatPublishedRelativeDate(locale: string, value: string | number | null, referenceNowMs?: number): string | null;
29
29
  /**
30
30
  * Month-year label, e.g. "Jun 2023" — transcribed from the hosted board's
31
- * `formatMonthYear` (golden-tested in-monorepo). The `T00:00:00` suffix
31
+ * `formatMonthYear`. The `T00:00:00` suffix
32
32
  * prevents timezone-related off-by-one-month issues on date-only strings.
33
33
  */
34
34
  declare function formatMonthYear(locale: string, dateStr: string): string;
@@ -38,7 +38,7 @@ declare function formatMonthYear(locale: string, dateStr: string): string;
38
38
  * `PublicJobCard` shape a list card renders — computing the card's
39
39
  * pre-resolved `locationLabel`/`remoteLocationLabel` from the full job's
40
40
  * fields. Board language is required because the computed location label is
41
- * display text (ADR-0057).
41
+ * display text.
42
42
  */
43
43
  declare function fullJobToCard(locale: string, job: PublicJob): PublicJobCard;
44
44
 
@@ -59,7 +59,7 @@ declare function fieldLabel(locale: string, value: string | null, labels?: Board
59
59
 
60
60
  /**
61
61
  * Location display labels for job cards and detail pages, in the board
62
- * language (required leading parameter, ADR-0057). The wrapper words
62
+ * language. The wrapper words
63
63
  * ("Remote", "(hybrid)", "Worldwide") follow the hosted board's current
64
64
  * English-only rendering; place names arrive already board-language from the
65
65
  * wire (the API serves canonical, localized labels).
@@ -84,8 +84,7 @@ declare function cardLocationLabel(locale: string, job: Pick<PublicJobCard, 'rem
84
84
  * `<title>`/`<description>` sentence FRAMES, keyed by the board language
85
85
  * (`board.context().language`), NOT by any visitor locale.
86
86
  *
87
- * Transcribed from the hosted board's `salary-lexicon.ts` (CAV-352 /
88
- * ADR-0012) and golden-tested against it in-monorepo (ADR-0057): the two
87
+ * Transcribed from the hosted board's `salary-lexicon.ts` and tested against it : the two
89
88
  * copies cannot drift silently. The `de` strings are native-reviewed.
90
89
  * Unseeded locales fall back to the English source WORDS while number and
91
90
  * currency formatting stays locale-correct.
@@ -229,7 +228,7 @@ interface SalaryTimeframeOverrides {
229
228
  }
230
229
  /**
231
230
  * Format a per-job salary range in the BOARD language
232
- * (`board.context().language` — required, never defaulted; see ADR-0057).
231
+ * (`board.context().language` — required, never defaulted; see ).
233
232
  * The fixed words (timeframe, "From"/"Up to") come from
234
233
  * `getSalaryLexicon(language)` with precedence owner-override > lexicon >
235
234
  * English source. Currency placement is gated: `en` keeps the legacy manual
@@ -251,7 +250,7 @@ declare function companyIntro(summary: string | null, description: string | null
251
250
  * permit taxonomy (`GET /v1/taxonomies/remote-permits`), published so a
252
251
  * picker on any surface offers exactly the set the API accepts. Mirrors the
253
252
  * platform's canonical `COUNTRIES` dataset (`world-countries` minus `KP`,
254
- * plus `XK`/Kosovo); an in-monorepo parity test asserts the mirror cannot
253
+ * plus `XK`/Kosovo); an parity test asserts the mirror cannot
255
254
  * drift. Codes only — display names localize at render via
256
255
  * `countryOptions(language)`.
257
256
  */
@@ -263,7 +262,7 @@ interface CountryOption {
263
262
  }
264
263
  /**
265
264
  * The complete country option list, display-named in the BOARD language
266
- * (required leading parameter, ADR-0057) and sorted by that language's
265
+ * and sorted by that language's
267
266
  * collation — the shape a country picker renders. Falls back to the bare
268
267
  * code when the runtime cannot resolve the language or name a region.
269
268
  */
@@ -271,15 +270,14 @@ declare function countryOptions(language: string): CountryOption[];
271
270
 
272
271
  /**
273
272
  * Resolve a job's opaque `customFieldValues` into ordered, display-ready
274
- * entries for the "Additional details" section — the client-side twin of the
275
- * hosted `resolveCustomFieldDisplay` (apps/web/lib/jobs/job-form-config/
276
- * custom-field-display.ts). Pure. Iterates the *definitions* (from board
273
+ * entries for the "Additional details" section, matching the hosted board's
274
+ * display behavior. Pure. Iterates the *definitions* (from board
277
275
  * context) in config order, so display order is operator-controlled, orphan
278
276
  * values (deleted definitions) are never inspected, and empty values drop per
279
277
  * field. Select values resolve their stored option KEY to the current label
280
278
  * (rename-safe); an option with no current match is dropped. Booleans stay raw
281
279
  * (a discriminated `kind`) — the render layer authors the "Yes"/"No" chrome
282
- * (English; localized copy is the use-intl follow-up).
280
+ * (English; localized copy is the use-intl future release).
283
281
  */
284
282
  type CustomFieldDisplayEntry = {
285
283
  key: string;