@cavuno/board 1.21.1 → 1.23.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.
package/dist/index.mjs CHANGED
@@ -109,7 +109,7 @@ async function clearSession(storage) {
109
109
  }
110
110
 
111
111
  // src/version.ts
112
- var SDK_VERSION = "1.21.1";
112
+ var SDK_VERSION = "1.23.0";
113
113
 
114
114
  // src/client.ts
115
115
  function isRawBody(body) {
@@ -307,6 +307,35 @@ function authNamespace(client) {
307
307
  body
308
308
  });
309
309
  },
310
+ /**
311
+ * Verify the signed-in board user's email with the 6-digit code from the
312
+ * verification email (requires the bearer). Resolves void (204); an
313
+ * invalid/expired code is a 401 `BoardApiError`. Distinct from the
314
+ * anonymous magic-link `verifyEmail({ token })`.
315
+ *
316
+ * @example
317
+ * await board.auth.verifyEmailWithCode({ code: '123456' });
318
+ */
319
+ verifyEmailWithCode(body, options) {
320
+ return client.fetch("/auth/verify-email/otp", {
321
+ ...options,
322
+ method: "POST",
323
+ body
324
+ });
325
+ },
326
+ /**
327
+ * Re-send the verification email (fresh code + magic link) to the signed-in
328
+ * board user. Resolves void (204); no-op if already verified.
329
+ *
330
+ * @example
331
+ * await board.auth.resendVerification();
332
+ */
333
+ resendVerification(options) {
334
+ return client.fetch("/auth/verify-email/resend", {
335
+ ...options,
336
+ method: "POST"
337
+ });
338
+ },
310
339
  /**
311
340
  * Request a password-reset email. Always resolves (204) whether or
312
341
  * not the email exists — no account oracle.
@@ -829,6 +858,53 @@ function jobsNamespace(client) {
829
858
  query
830
859
  }
831
860
  );
861
+ },
862
+ /**
863
+ * Apply to a job natively (ADR-0054). Optional auth: a signed-in candidate
864
+ * applies from their profile (omit name/email); a guest supplies them
865
+ * (allowed only when the board permits applications without sign-up).
866
+ * Idempotent — a repeat apply returns the existing application.
867
+ *
868
+ * @example
869
+ * const application = await board.jobs.apply('senior-chef', {
870
+ * coverNote: 'Excited to cook here.',
871
+ * });
872
+ */
873
+ apply(jobSlug, body, options) {
874
+ return client.fetch(
875
+ `/jobs/${encodeURIComponent(jobSlug)}/apply`,
876
+ { ...options, method: "POST", body: body ?? {} }
877
+ );
878
+ },
879
+ /**
880
+ * Upload + attach a resume to an application (multipart). Signed-in
881
+ * candidates target their own application for the job; a guest passes the
882
+ * `applicationId` returned by `apply`. Returns the updated application.
883
+ *
884
+ * @example
885
+ * await board.jobs.uploadApplicationResume('senior-chef', file);
886
+ */
887
+ uploadApplicationResume(jobSlug, file, opts, options) {
888
+ const form = new FormData();
889
+ form.append("file", file);
890
+ if (opts?.applicationId) form.append("applicationId", opts.applicationId);
891
+ return client.fetch(
892
+ `/jobs/${encodeURIComponent(jobSlug)}/apply/resume`,
893
+ { ...options, method: "POST", body: form }
894
+ );
895
+ },
896
+ /**
897
+ * The authenticated candidate's application for this job (the apply-button
898
+ * "have I applied?" check). Throws a 404 `BoardApiError` when there is none.
899
+ *
900
+ * @example
901
+ * const application = await board.jobs.myApplication('senior-chef');
902
+ */
903
+ myApplication(jobSlug, options) {
904
+ return client.fetch(
905
+ `/jobs/${encodeURIComponent(jobSlug)}/application`,
906
+ options
907
+ );
832
908
  }
833
909
  };
834
910
  }
@@ -1468,6 +1544,185 @@ function meNamespace(client) {
1468
1544
  }
1469
1545
  }
1470
1546
  },
1547
+ /**
1548
+ * The authenticated board user's job-alert preferences (ADR-0053) —
1549
+ * a collection (up to 10). Creating one is active immediately (no
1550
+ * double opt-in — the authenticated action is the consent). There is no
1551
+ * pause: `remove` is the only way to stop an alert.
1552
+ */
1553
+ alerts: {
1554
+ /**
1555
+ * List my job alerts.
1556
+ *
1557
+ * @example
1558
+ * const { data } = await board.me.alerts.list();
1559
+ */
1560
+ list(options) {
1561
+ return client.fetch("/me/alerts", options);
1562
+ },
1563
+ /**
1564
+ * Create a new active job alert.
1565
+ *
1566
+ * @example
1567
+ * await board.me.alerts.create({
1568
+ * frequency: 'weekly',
1569
+ * jobFunctions: ['engineering'],
1570
+ * remoteOptions: ['remote'],
1571
+ * });
1572
+ */
1573
+ create(body, options) {
1574
+ return client.fetch("/me/alerts", {
1575
+ ...options,
1576
+ method: "POST",
1577
+ body
1578
+ });
1579
+ },
1580
+ /**
1581
+ * Retrieve one of my job alerts.
1582
+ *
1583
+ * @example
1584
+ * const alert = await board.me.alerts.retrieve(alertId);
1585
+ */
1586
+ retrieve(alertId, options) {
1587
+ return client.fetch(
1588
+ `/me/alerts/${encodeURIComponent(alertId)}`,
1589
+ options
1590
+ );
1591
+ },
1592
+ /**
1593
+ * Replace a job alert's filters + frequency in full. Returns the updated
1594
+ * alert.
1595
+ *
1596
+ * @example
1597
+ * await board.me.alerts.update(alertId, {
1598
+ * frequency: 'daily',
1599
+ * placeIds: ['ChIJ…'],
1600
+ * });
1601
+ */
1602
+ update(alertId, body, options) {
1603
+ return client.fetch(
1604
+ `/me/alerts/${encodeURIComponent(alertId)}`,
1605
+ { ...options, method: "PUT", body }
1606
+ );
1607
+ },
1608
+ /**
1609
+ * Delete a job alert. Resolves void on success (204).
1610
+ *
1611
+ * @example
1612
+ * await board.me.alerts.remove(alertId);
1613
+ */
1614
+ remove(alertId, options) {
1615
+ return client.fetch(`/me/alerts/${encodeURIComponent(alertId)}`, {
1616
+ ...options,
1617
+ method: "DELETE"
1618
+ });
1619
+ }
1620
+ },
1621
+ /**
1622
+ * The authenticated candidate's applications (ADR-0054). Apply itself lives
1623
+ * on the job (`board.jobs.apply` — it is optional-auth); these manage the
1624
+ * applications the candidate has already submitted, keyed by `applicationId`.
1625
+ */
1626
+ applications: {
1627
+ /**
1628
+ * List my applications, newest first.
1629
+ *
1630
+ * @example
1631
+ * const { data } = await board.me.applications.list();
1632
+ */
1633
+ list(query, options) {
1634
+ return client.fetch("/me/applications", {
1635
+ ...options,
1636
+ query
1637
+ });
1638
+ },
1639
+ /**
1640
+ * Retrieve one of my applications by id.
1641
+ *
1642
+ * @example
1643
+ * const application = await board.me.applications.retrieve(id);
1644
+ */
1645
+ retrieve(applicationId, options) {
1646
+ return client.fetch(
1647
+ `/me/applications/${encodeURIComponent(applicationId)}`,
1648
+ options
1649
+ );
1650
+ },
1651
+ /**
1652
+ * Edit the candidate-facing facts of an application (merge-patch). Only
1653
+ * while it is still editable. Returns the updated application.
1654
+ *
1655
+ * @example
1656
+ * await board.me.applications.updateFacts(id, { coverNote: '…' });
1657
+ */
1658
+ updateFacts(applicationId, body, options) {
1659
+ return client.fetch(
1660
+ `/me/applications/${encodeURIComponent(applicationId)}`,
1661
+ { ...options, method: "PATCH", body }
1662
+ );
1663
+ },
1664
+ /**
1665
+ * Withdraw (permanently delete) an application. Resolves void on 204.
1666
+ *
1667
+ * @example
1668
+ * await board.me.applications.withdraw(id);
1669
+ */
1670
+ withdraw(applicationId, options) {
1671
+ return client.fetch(
1672
+ `/me/applications/${encodeURIComponent(applicationId)}/withdraw`,
1673
+ { ...options, method: "POST" }
1674
+ );
1675
+ }
1676
+ },
1677
+ /**
1678
+ * The candidate's resume (ADR-0055). `upload` starts an async parse that
1679
+ * auto-populates the profile — it returns `parseStatus: 'parsing'`; poll
1680
+ * `retrieve()` until `parsed`/`failed`, then re-read `profile.*`.
1681
+ */
1682
+ resume: {
1683
+ /**
1684
+ * Upload a resume and start the async parse. Returns the resume with
1685
+ * `parseStatus: 'parsing'`.
1686
+ *
1687
+ * @example
1688
+ * await board.me.resume.upload(file, { keepResumeOnFile: true });
1689
+ */
1690
+ upload(file, opts, options) {
1691
+ const form = new FormData();
1692
+ form.append("resume", file);
1693
+ if (opts?.keepResumeOnFile) form.append("keepResumeOnFile", "true");
1694
+ if (opts?.importMode) form.append("importMode", opts.importMode);
1695
+ if (opts?.confirmReplaceAll) form.append("confirmReplaceAll", "true");
1696
+ return client.fetch("/me/resume", {
1697
+ ...options,
1698
+ method: "POST",
1699
+ body: form
1700
+ });
1701
+ },
1702
+ /**
1703
+ * Retrieve my resume state (parse status + stored file). Poll this after
1704
+ * `upload` until `parseStatus` is `parsed` or `failed`.
1705
+ *
1706
+ * @example
1707
+ * const resume = await board.me.resume.retrieve();
1708
+ */
1709
+ retrieve(options) {
1710
+ return client.fetch("/me/resume", options);
1711
+ },
1712
+ /**
1713
+ * Delete my stored resume file + withdraw keep-on-file consent (parsed
1714
+ * profile fields stay). Resolves void (204).
1715
+ *
1716
+ * @example
1717
+ * await board.me.resume.delete();
1718
+ */
1719
+ delete(options) {
1720
+ return client.fetch("/me/resume", {
1721
+ ...options,
1722
+ method: "DELETE"
1723
+ });
1724
+ }
1725
+ },
1471
1726
  savedJobs: {
1472
1727
  /**
1473
1728
  * List the authenticated user's saved jobs (each embeds the full
@@ -1509,6 +1764,256 @@ function meNamespace(client) {
1509
1764
  { ...options, method: "DELETE", query }
1510
1765
  );
1511
1766
  }
1767
+ },
1768
+ /**
1769
+ * The authenticated board user's messaging inbox (doc 34 / ADR-0053).
1770
+ * The v1 surface is polled REST — there is no realtime primitive; poll
1771
+ * `list` / `listMessages` / `unreadCount` on an interval (3–5s is the
1772
+ * reference cadence) for near-live updates.
1773
+ */
1774
+ conversations: {
1775
+ /**
1776
+ * List my conversations (each page sorted most-recent-activity-first;
1777
+ * cross-page cursor order is approximate — see the API docs). `archived:
1778
+ * true` returns the archived view. Poll for inbox liveness.
1779
+ *
1780
+ * @example
1781
+ * const { data } = await board.me.conversations.list({ limit: 20 });
1782
+ */
1783
+ list(query, options) {
1784
+ return client.fetch("/me/conversations", {
1785
+ ...options,
1786
+ query
1787
+ });
1788
+ },
1789
+ /**
1790
+ * The count of distinct conversations with an unread message — the
1791
+ * inbox badge. Poll for liveness.
1792
+ *
1793
+ * @example
1794
+ * const { count } = await board.me.conversations.unreadCount();
1795
+ */
1796
+ unreadCount(options) {
1797
+ return client.fetch(
1798
+ "/me/conversations/unread-count",
1799
+ options
1800
+ );
1801
+ },
1802
+ /**
1803
+ * A conversation's header — live-resolved counterparty identity, the
1804
+ * viewer's role, and the viewer's last-read pointer. The messages are a
1805
+ * separate paginated call (`listMessages`).
1806
+ *
1807
+ * @example
1808
+ * const convo = await board.me.conversations.retrieve(id);
1809
+ */
1810
+ retrieve(id, options) {
1811
+ return client.fetch(
1812
+ `/me/conversations/${encodeURIComponent(id)}`,
1813
+ options
1814
+ );
1815
+ },
1816
+ /**
1817
+ * A conversation's messages, oldest-first (append order). Unsent
1818
+ * messages are tombstones (empty `body`, `deletedAt` set). Poll for the
1819
+ * live thread.
1820
+ *
1821
+ * @example
1822
+ * const { data } = await board.me.conversations.listMessages(id, { limit: 50 });
1823
+ */
1824
+ listMessages(id, query, options) {
1825
+ return client.fetch(
1826
+ `/me/conversations/${encodeURIComponent(id)}/messages`,
1827
+ { ...options, query }
1828
+ );
1829
+ },
1830
+ /**
1831
+ * Cold-initiate a conversation with a candidate (employer-only).
1832
+ * Converges on the existing thread. Returns the created message.
1833
+ *
1834
+ * @example
1835
+ * const msg = await board.me.conversations.start({ candidateBoardUserId, body: 'Hi!' });
1836
+ */
1837
+ start(body, options) {
1838
+ return client.fetch("/me/conversations", {
1839
+ ...options,
1840
+ method: "POST",
1841
+ body
1842
+ });
1843
+ },
1844
+ /**
1845
+ * Message an applicant from the ATS (application context, outside the
1846
+ * talent paywall). Returns the created message.
1847
+ *
1848
+ * @example
1849
+ * const msg = await board.me.conversations.startAboutApplication({ applicationId, body: '…' });
1850
+ */
1851
+ startAboutApplication(body, options) {
1852
+ return client.fetch("/me/conversations/about-application", {
1853
+ ...options,
1854
+ method: "POST",
1855
+ body
1856
+ });
1857
+ },
1858
+ /**
1859
+ * Reply in an existing conversation. Returns the created message.
1860
+ *
1861
+ * @example
1862
+ * const msg = await board.me.conversations.reply(id, { body: 'Sounds good' });
1863
+ */
1864
+ reply(id, body, options) {
1865
+ return client.fetch(
1866
+ `/me/conversations/${encodeURIComponent(id)}/reply`,
1867
+ { ...options, method: "POST", body }
1868
+ );
1869
+ },
1870
+ /**
1871
+ * Mark a conversation read for the viewer. Idempotent.
1872
+ *
1873
+ * @example
1874
+ * await board.me.conversations.markRead(id);
1875
+ */
1876
+ markRead(id, options) {
1877
+ return client.fetch(
1878
+ `/me/conversations/${encodeURIComponent(id)}/read`,
1879
+ { ...options, method: "POST" }
1880
+ );
1881
+ },
1882
+ /**
1883
+ * Archive a conversation for the viewer (per-side). Idempotent.
1884
+ *
1885
+ * @example
1886
+ * await board.me.conversations.archive(id);
1887
+ */
1888
+ archive(id, options) {
1889
+ return client.fetch(
1890
+ `/me/conversations/${encodeURIComponent(id)}/archive`,
1891
+ { ...options, method: "POST" }
1892
+ );
1893
+ },
1894
+ /**
1895
+ * Move an archived conversation back to the main inbox. Idempotent.
1896
+ *
1897
+ * @example
1898
+ * await board.me.conversations.unarchive(id);
1899
+ */
1900
+ unarchive(id, options) {
1901
+ return client.fetch(
1902
+ `/me/conversations/${encodeURIComponent(id)}/unarchive`,
1903
+ { ...options, method: "POST" }
1904
+ );
1905
+ },
1906
+ /**
1907
+ * The existing employer↔candidate conversation id (or null). Tier-3
1908
+ * talent-contact helper — route to an existing thread instead of opening
1909
+ * a composer.
1910
+ *
1911
+ * @example
1912
+ * const { conversationId } = await board.me.conversations.findExisting({ candidateBoardUserId });
1913
+ */
1914
+ findExisting(query, options) {
1915
+ return client.fetch(
1916
+ "/me/conversations/find-existing",
1917
+ { ...options, query }
1918
+ );
1919
+ }
1920
+ },
1921
+ /**
1922
+ * Blocking (doc 34 §E): list / add / remove blocks + a Tier-3 status check.
1923
+ */
1924
+ blocks: {
1925
+ /**
1926
+ * The users I've blocked.
1927
+ *
1928
+ * @example
1929
+ * const { data } = await board.me.blocks.list();
1930
+ */
1931
+ list(options) {
1932
+ return client.fetch("/me/blocks", options);
1933
+ },
1934
+ /**
1935
+ * Block a user (silent). Idempotent.
1936
+ *
1937
+ * @example
1938
+ * await board.me.blocks.create({ boardUserId });
1939
+ */
1940
+ create(body, options) {
1941
+ return client.fetch("/me/blocks", {
1942
+ ...options,
1943
+ method: "POST",
1944
+ body
1945
+ });
1946
+ },
1947
+ /**
1948
+ * Unblock a user. Idempotent.
1949
+ *
1950
+ * @example
1951
+ * await board.me.blocks.remove(boardUserId);
1952
+ */
1953
+ remove(boardUserId, options) {
1954
+ return client.fetch(
1955
+ `/me/blocks/${encodeURIComponent(boardUserId)}`,
1956
+ { ...options, method: "DELETE" }
1957
+ );
1958
+ },
1959
+ /**
1960
+ * Whether I've blocked a user (Tier-3 helper).
1961
+ *
1962
+ * @example
1963
+ * const { blocked } = await board.me.blocks.status(boardUserId);
1964
+ */
1965
+ status(boardUserId, options) {
1966
+ return client.fetch(
1967
+ `/me/blocks/${encodeURIComponent(boardUserId)}`,
1968
+ options
1969
+ );
1970
+ }
1971
+ },
1972
+ /**
1973
+ * Message-scoped actions (doc 34 §E): edit / unsend your own messages
1974
+ * (15-minute window), and report a message addressed to you.
1975
+ */
1976
+ messages: {
1977
+ /**
1978
+ * Edit one of your own messages (within the 15-minute window). Returns
1979
+ * the updated message.
1980
+ *
1981
+ * @example
1982
+ * const msg = await board.me.messages.edit(id, { body: 'fixed typo' });
1983
+ */
1984
+ edit(id, body, options) {
1985
+ return client.fetch(`/me/messages/${encodeURIComponent(id)}`, {
1986
+ ...options,
1987
+ method: "PATCH",
1988
+ body
1989
+ });
1990
+ },
1991
+ /**
1992
+ * Unsend (soft-delete) one of your own messages (within the 15-minute
1993
+ * window). Idempotent. Returns the tombstoned message (empty `body`).
1994
+ *
1995
+ * @example
1996
+ * await board.me.messages.unsend(id);
1997
+ */
1998
+ unsend(id, options) {
1999
+ return client.fetch(`/me/messages/${encodeURIComponent(id)}`, {
2000
+ ...options,
2001
+ method: "DELETE"
2002
+ });
2003
+ },
2004
+ /**
2005
+ * Report a message addressed to you for moderation. Auto-blocks the
2006
+ * author.
2007
+ *
2008
+ * @example
2009
+ * const { blocked } = await board.me.messages.report(id, { reason: 'spam' });
2010
+ */
2011
+ report(id, body, options) {
2012
+ return client.fetch(
2013
+ `/me/messages/${encodeURIComponent(id)}/report`,
2014
+ { ...options, method: "POST", body }
2015
+ );
2016
+ }
1512
2017
  }
1513
2018
  };
1514
2019
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavuno/board",
3
- "version": "1.21.1",
3
+ "version": "1.23.0",
4
4
  "description": "Typed isomorphic client for the Cavuno Board API",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.21.1",
2
+ "version": "1.23.0",
3
3
  "skills": [
4
4
  {
5
5
  "name": "cavuno-board-auth",