@cavuno/board 1.44.0 → 2.0.1

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 +22 -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 +38 -349
  10. package/dist/{board-DZCw7A6P.d.ts → board-DKXyxwNN.d.ts} +2 -2
  11. package/dist/{board-BwFW1aU2.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 +38 -345
  15. package/dist/doctor.mjs +37 -344
  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-BVazo4mA.d.ts → jobs-CuRzTDb1.d.mts} +15 -13
  29. package/dist/{jobs-CSMshXGV.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-DMQsjLrV.d.ts → salaries-BOpR51Ny.d.mts} +3 -3
  41. package/dist/{salaries-IJlchnWk.d.mts → salaries-QoNpzRCT.d.ts} +3 -3
  42. package/dist/{search-B7gr_wOd.d.ts → search-B5ROY6PK.d.ts} +2 -2
  43. package/dist/{search-B6FJifRE.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 -3
  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-CoL3oYpG.d.mts +0 -5296
  84. package/dist/_spec-CoL3oYpG.d.ts +0 -5296
package/dist/doctor.mjs CHANGED
@@ -187,6 +187,25 @@ function isOffendingSink(lines, index) {
187
187
  if (!hasCookieWriteSink(stripped)) return false;
188
188
  return DOMAIN_SCOPE.test(statementWindow(lines, index));
189
189
  }
190
+ var GENERATED_DIRS = /* @__PURE__ */ new Set([
191
+ "paraglide",
192
+ "generated",
193
+ "_generated",
194
+ "__generated__"
195
+ ]);
196
+ var GENERATED_FILE = /\.gen\.(?:ts|tsx|js|jsx|mjs|cjs)$/;
197
+ var GENERATED_BANNER = /@generated|generated by|generated from|auto-?generated|do not edit|don't edit/i;
198
+ var BANNER_SCAN_LINES = 5;
199
+ function hasGeneratedBanner(text) {
200
+ const lines = text.split(/\r?\n/);
201
+ const limit = Math.min(lines.length, BANNER_SCAN_LINES);
202
+ for (let i = 0; i < limit; i += 1) {
203
+ const line = lines[i];
204
+ if (!isCommentLine(line)) return false;
205
+ if (GENERATED_BANNER.test(line)) return true;
206
+ }
207
+ return false;
208
+ }
190
209
  function walkSourceFiles(dir, out) {
191
210
  let entries;
192
211
  try {
@@ -196,6 +215,7 @@ function walkSourceFiles(dir, out) {
196
215
  }
197
216
  for (const name of entries) {
198
217
  if (name === "node_modules" || name.startsWith(".")) continue;
218
+ if (GENERATED_DIRS.has(name) || GENERATED_FILE.test(name)) continue;
199
219
  const full = join(dir, name);
200
220
  let st;
201
221
  try {
@@ -235,6 +255,7 @@ function checkCookieCodecConformance(projectRoot) {
235
255
  } catch {
236
256
  continue;
237
257
  }
258
+ if (hasGeneratedBanner(text)) continue;
238
259
  const lines = text.split(/\r?\n/);
239
260
  for (let i = 0; i < lines.length; i += 1) {
240
261
  if (!isOffendingSink(lines, i)) continue;
@@ -245,7 +266,7 @@ function checkCookieCodecConformance(projectRoot) {
245
266
  return [
246
267
  COOKIE(
247
268
  "pass",
248
- "no domain-scoped Set-Cookie or document.cookie writes in src/"
269
+ "no domain-scoped Set-Cookie or document.cookie writes in app-authored src/ (generated output skipped)"
249
270
  )
250
271
  ];
251
272
  }
@@ -371,86 +392,18 @@ async function runReadProbes(fetchImpl, frontendUrl) {
371
392
  ];
372
393
  }
373
394
 
374
- // src/doctor/sandbox.ts
375
- var SANDBOX_GATE = record("sandbox.persona-gate", 1);
376
- var EXPECTED_PERSONA_COUNT = 8;
377
- function skipSandboxPersonaGate(reason) {
378
- return SANDBOX_GATE("skip", reason);
379
- }
380
- async function checkSandboxPersonaGate(fetchImpl, env, boardContext) {
381
- if (boardContext === null) {
382
- return SANDBOX_GATE(
383
- "skip",
384
- "board did not resolve \u2014 fix static.board first"
385
- );
386
- }
387
- const url = `${apiBase(env.apiUrl)}/v1/boards/${encodeURIComponent(env.boardKey)}/sandbox/personas`;
388
- const result = await probe(fetchImpl, url);
389
- if (boardContext.sandbox !== true) {
390
- return result.status === 404 ? SANDBOX_GATE(
391
- "pass",
392
- "sandbox persona endpoint refuses (404) on a non-sandbox board"
393
- ) : SANDBOX_GATE(
394
- "fail",
395
- `sandbox persona endpoint is reachable on a NON-sandbox board (HTTP ${result.status}) \u2014 the capability gate is not holding`
396
- );
397
- }
398
- if (!result.ok) {
399
- return SANDBOX_GATE(
400
- "fail",
401
- `sandbox persona roster did not resolve (HTTP ${result.status}) \u2014 the persona seed may have failed`
402
- );
403
- }
404
- let personas;
405
- let password;
406
- try {
407
- const parsed = JSON.parse(result.body);
408
- personas = parsed.personas;
409
- password = parsed.password;
410
- } catch {
411
- return SANDBOX_GATE(
412
- "fail",
413
- "sandbox persona endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
414
- );
415
- }
416
- if (!Array.isArray(personas) || personas.length !== EXPECTED_PERSONA_COUNT) {
417
- return SANDBOX_GATE(
418
- "fail",
419
- `expected ${EXPECTED_PERSONA_COUNT} personas, got ${Array.isArray(personas) ? personas.length : "a non-array"} \u2014 the persona seed is incomplete`
420
- );
421
- }
422
- const unseeded = personas.filter((persona) => persona.seeded !== true);
423
- if (unseeded.length > 0) {
424
- const ids = unseeded.map((persona) => typeof persona.id === "string" ? persona.id : "?").join(", ");
425
- return SANDBOX_GATE(
426
- "fail",
427
- `${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`
428
- );
429
- }
430
- if (typeof password !== "string" || password.length === 0) {
431
- return SANDBOX_GATE(
432
- "fail",
433
- "roster present but the published password is missing"
434
- );
435
- }
436
- return SANDBOX_GATE(
437
- "pass",
438
- `sandbox roster complete and seeded (${EXPECTED_PERSONA_COUNT} personas)`
439
- );
440
- }
441
-
442
395
  // src/doctor/theme.ts
443
396
  import { createHash } from "crypto";
444
397
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
445
398
  import { join as join2 } from "path";
446
399
  var THEME = record("static.theme", 1);
447
- function checkThemeFreshness(projectRoot, context) {
400
+ function checkThemeFreshness(projectRoot) {
448
401
  const tokensPath = join2(projectRoot, "src/tokens.css");
449
402
  if (!existsSync2(tokensPath)) {
450
403
  return [
451
404
  THEME(
452
405
  "skip",
453
- "board is not tokens-migrated (ADR-0065) \u2014 no src/tokens.css"
406
+ "no src/tokens.css \u2014 local theme freshness check not applicable"
454
407
  )
455
408
  ];
456
409
  }
@@ -467,232 +420,9 @@ function checkThemeFreshness(projectRoot, context) {
467
420
  )
468
421
  ];
469
422
  }
470
- if (!context) {
471
- return [
472
- THEME(
473
- "skip",
474
- "local derivations fresh; platform snapshot unverified \u2014 board context unavailable"
475
- )
476
- ];
477
- }
478
- if (context.themeSnapshotHash !== tokensHash) {
479
- return [
480
- THEME(
481
- "fail",
482
- `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\``
483
- )
484
- ];
485
- }
486
423
  return [
487
- THEME(
488
- "pass",
489
- `tokens.css \u21C4 resolved module \u21C4 platform snapshot (${tokensHash.slice(0, 12)}\u2026)`
490
- )
491
- ];
492
- }
493
-
494
- // src/doctor/writes.ts
495
- var WRITE = {
496
- board: record("write.board", 3),
497
- register: record("write.register", 3),
498
- login: record("write.login", 3),
499
- email: record("write.email", 3),
500
- apply: record("write.apply", 3),
501
- alert: record("write.alert", 3)
502
- };
503
- var DEPENDENT_CHECKS = [
504
- WRITE.register,
505
- WRITE.login,
506
- WRITE.email,
507
- WRITE.apply,
508
- WRITE.alert
509
- ];
510
- function skipWriteProbes(reason) {
511
- return Object.values(WRITE).map((make) => make("skip", reason));
512
- }
513
- var FETCH_TIMEOUT_MS2 = 1e4;
514
- var RESEND_API_BASE = "https://api.resend.com";
515
- async function request(fetchImpl, url, init) {
516
- try {
517
- const response = await fetchImpl(url, {
518
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2),
519
- ...init
520
- });
521
- let json = null;
522
- try {
523
- json = await response.json();
524
- } catch {
525
- json = null;
526
- }
527
- return { ok: response.ok, status: response.status, json };
528
- } catch (error) {
529
- return {
530
- ok: false,
531
- status: 0,
532
- json: { error: error instanceof Error ? error.message : String(error) }
533
- };
534
- }
535
- }
536
- function post(fetchImpl, url, body, bearer) {
537
- return request(fetchImpl, url, {
538
- method: "POST",
539
- headers: {
540
- "content-type": "application/json",
541
- accept: "application/json",
542
- ...bearer ? { authorization: `Bearer ${bearer}` } : {}
543
- },
544
- body: JSON.stringify(body)
545
- });
546
- }
547
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
548
- async function observeVerificationEmail(fetchImpl, apiKey, recipient, pollMs, timeoutMs) {
549
- const deadline = Date.now() + timeoutMs;
550
- const subjectMarker = `[To: ${recipient}]`;
551
- do {
552
- const list = await request(
553
- fetchImpl,
554
- `${RESEND_API_BASE}/emails?limit=20`,
555
- {
556
- headers: { authorization: `Bearer ${apiKey}` }
557
- }
558
- );
559
- if (!list.ok) {
560
- return WRITE.email(
561
- "fail",
562
- `Resend list returned HTTP ${list.status} \u2014 wrong RESEND_API_KEY?`
563
- );
564
- }
565
- const items = list.json?.data ?? [];
566
- const match = items.find(
567
- (item) => item.subject?.includes(subjectMarker) || item.to?.includes(recipient)
568
- );
569
- if (match) {
570
- return WRITE.email(
571
- "pass",
572
- `verification send observed in Resend for ${recipient}`
573
- );
574
- }
575
- await sleep(pollMs);
576
- } while (Date.now() < deadline);
577
- return WRITE.email(
578
- "fail",
579
- `no verification send for ${recipient} appeared in Resend within ${timeoutMs}ms`
580
- );
581
- }
582
- async function runWriteProbes(options) {
583
- const { fetchImpl } = options;
584
- const base = `${apiBase(options.env.apiUrl)}/v1/boards/${encodeURIComponent(options.env.boardKey)}`;
585
- const nonce = options.nonce ?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
586
- const email = `doctor+${nonce}@cavuno.com`;
587
- const password = `doctor-probe-${nonce}-A1!`;
588
- let context = options.boardContext ?? null;
589
- if (context === null) {
590
- const r = await request(fetchImpl, base);
591
- if (!r.ok) {
592
- return [
593
- WRITE.board("fail", `board context did not resolve (HTTP ${r.status})`),
594
- ...DEPENDENT_CHECKS.map(
595
- (make) => make("skip", "not run \u2014 the write gate failed (see write.board)")
596
- )
597
- ];
598
- }
599
- context = r.json ?? {};
600
- }
601
- if (context.sandbox !== true) {
602
- return [
603
- WRITE.board(
604
- "fail",
605
- "refusing write probes: this board is not the platform sandbox (`sandbox` is not true) \u2014 point PUBLIC_CAVUNO_BOARD at the sandbox pk_"
606
- ),
607
- ...DEPENDENT_CHECKS.map(
608
- (make) => make("skip", "not run \u2014 the write gate failed (see write.board)")
609
- )
610
- ];
611
- }
612
- const results = [
613
- WRITE.board("pass", "board is the platform sandbox")
424
+ THEME("pass", `tokens.css \u21C4 resolved module (${tokensHash.slice(0, 12)}\u2026)`)
614
425
  ];
615
- const registered = await post(fetchImpl, `${base}/auth/register`, {
616
- role: "candidate",
617
- method: "emailpass",
618
- email,
619
- password,
620
- displayName: "Doctor Probe"
621
- });
622
- const sessionOk = (r) => r.ok && typeof r.json?.accessToken === "string";
623
- results.push(
624
- sessionOk(registered) ? WRITE.register("pass", `candidate registered (${email})`) : WRITE.register(
625
- "fail",
626
- `register returned HTTP ${registered.status}` + (registered.status === 429 ? " \u2014 rate-limited: register allows 5 signups / 15 min per IP; wait before rerunning" : "")
627
- )
628
- );
629
- let accessToken = null;
630
- if (sessionOk(registered)) {
631
- const login = await post(fetchImpl, `${base}/auth/login`, {
632
- email,
633
- password
634
- });
635
- if (sessionOk(login)) {
636
- accessToken = login.json.accessToken;
637
- results.push(WRITE.login("pass", "emailpass login returns a session"));
638
- } else {
639
- results.push(WRITE.login("fail", `login returned HTTP ${login.status}`));
640
- }
641
- } else {
642
- results.push(WRITE.login("skip", "not run \u2014 register failed"));
643
- }
644
- if (!sessionOk(registered)) {
645
- results.push(WRITE.email("skip", "not run \u2014 register failed"));
646
- } else if (!options.resendApiKey) {
647
- results.push(
648
- WRITE.email(
649
- "skip",
650
- "RESEND_API_KEY not set \u2014 the verification send was NOT verified (platform-operator check)"
651
- )
652
- );
653
- } else {
654
- results.push(
655
- await observeVerificationEmail(
656
- fetchImpl,
657
- options.resendApiKey,
658
- email,
659
- options.emailPollMs ?? 2e3,
660
- options.emailTimeoutMs ?? 3e4
661
- )
662
- );
663
- }
664
- if (!accessToken) {
665
- results.push(WRITE.apply("skip", "not run \u2014 no session (see above)"));
666
- } else {
667
- const listing = await request(fetchImpl, `${base}/jobs?limit=1`);
668
- const card = listing.json?.data?.[0];
669
- if (!listing.ok || !card?.slug) {
670
- results.push(
671
- WRITE.apply(
672
- "fail",
673
- listing.ok ? "the board has no jobs to apply to \u2014 is the sandbox seeded?" : `jobs listing returned HTTP ${listing.status}`
674
- )
675
- );
676
- } else {
677
- const applied = await post(
678
- fetchImpl,
679
- `${base}/jobs/${encodeURIComponent(card.slug)}/apply`,
680
- {},
681
- accessToken
682
- );
683
- results.push(
684
- applied.ok && typeof applied.json?.id === "string" ? WRITE.apply("pass", `applied to ${card.slug}`) : WRITE.apply("fail", `apply returned HTTP ${applied.status}`)
685
- );
686
- }
687
- }
688
- const alert = await post(fetchImpl, `${base}/job-alerts`, {
689
- email,
690
- consent: true
691
- });
692
- results.push(
693
- alert.ok ? WRITE.alert("pass", "job-alert subscription accepted") : WRITE.alert("fail", `job-alerts returned HTTP ${alert.status}`)
694
- );
695
- return results;
696
426
  }
697
427
 
698
428
  // src/doctor/run.ts
@@ -731,31 +461,21 @@ async function checkBoardResolves(fetchImpl, env) {
731
461
  `${apiBase(env.apiUrl)}/v1/boards/${encodeURIComponent(env.boardKey)}`
732
462
  );
733
463
  if (!result.ok) {
734
- return {
735
- result: STATIC_BOARD(
736
- "fail",
737
- `board did not resolve for this key (HTTP ${result.status}) \u2014 revoked or wrong key?`
738
- ),
739
- context: null
740
- };
464
+ return STATIC_BOARD(
465
+ "fail",
466
+ `board did not resolve for this key (HTTP ${result.status}) \u2014 revoked or wrong key?`
467
+ );
741
468
  }
742
- let parsed = null;
743
469
  try {
744
- parsed = JSON.parse(result.body);
470
+ const parsed = JSON.parse(result.body);
745
471
  if (typeof parsed !== "object" || parsed === null) throw new Error("shape");
746
472
  } catch {
747
- return {
748
- result: STATIC_BOARD(
749
- "fail",
750
- "board endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
751
- ),
752
- context: null
753
- };
473
+ return STATIC_BOARD(
474
+ "fail",
475
+ "board endpoint returned 200 but not JSON \u2014 proxy or captive portal in the way?"
476
+ );
754
477
  }
755
- return {
756
- result: STATIC_BOARD("pass", "publishable key resolves the board"),
757
- context: parsed
758
- };
478
+ return STATIC_BOARD("pass", "publishable key resolves the board");
759
479
  }
760
480
  var SKILL_ROOTS = [
761
481
  ".claude/skills",
@@ -818,46 +538,19 @@ async function runDoctor(options) {
818
538
  } else {
819
539
  results.push(STATIC_API("skip", "PUBLIC_CAVUNO_API_URL not set"));
820
540
  }
821
- let boardContext = null;
822
541
  if (envOk) {
823
- const resolved = await checkBoardResolves(fetchImpl, env);
824
- boardContext = resolved.context;
825
- results.push(resolved.result);
542
+ results.push(await checkBoardResolves(fetchImpl, env));
826
543
  } else {
827
544
  results.push(STATIC_BOARD("skip", "env checks failed \u2014 fix them first"));
828
545
  }
829
546
  results.push(checkSkillsFreshness(options.projectRoot ?? process.cwd()));
830
- results.push(
831
- ...checkThemeFreshness(options.projectRoot ?? process.cwd(), boardContext)
832
- );
547
+ results.push(...checkThemeFreshness(options.projectRoot ?? process.cwd()));
833
548
  results.push(
834
549
  ...checkCookieCodecConformance(options.projectRoot ?? process.cwd())
835
550
  );
836
- results.push(
837
- envOk ? await checkSandboxPersonaGate(fetchImpl, env, boardContext) : skipSandboxPersonaGate("env checks failed \u2014 fix them first")
838
- );
839
551
  results.push(
840
552
  ...options.frontendUrl ? await runReadProbes(fetchImpl, options.frontendUrl) : skipReadProbes("no --frontend <url> given")
841
553
  );
842
- if (!options.sandbox) {
843
- results.push(
844
- ...skipWriteProbes(
845
- "write probes not enabled \u2014 run with --sandbox against the platform sandbox"
846
- )
847
- );
848
- } else if (!envOk) {
849
- results.push(...skipWriteProbes("env checks failed \u2014 fix them first"));
850
- } else {
851
- results.push(
852
- ...await runWriteProbes({
853
- env,
854
- fetchImpl,
855
- resendApiKey: options.resendApiKey,
856
- nonce: options.writeProbeNonce,
857
- boardContext
858
- })
859
- );
860
- }
861
554
  return { results, summary: summarize(results) };
862
555
  }
863
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-CSMshXGV.mjs';
3
- import './_spec-CoL3oYpG.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-BVazo4mA.js';
3
- import './_spec-CoL3oYpG.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-CSMshXGV.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-BwFW1aU2.mjs';
5
- import './_spec-CoL3oYpG.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;