@byollm/protocol 0.1.0-alpha.54 → 0.1.0-alpha.56

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.js CHANGED
@@ -1023,12 +1023,73 @@ function verifyRequest(input) {
1023
1023
  return ok ? null : "bad-signature";
1024
1024
  }
1025
1025
 
1026
- // src/succession.ts
1026
+ // src/roster.ts
1027
+ import { Buffer as Buffer2 } from "buffer";
1027
1028
  import { z as z8 } from "zod";
1029
+ var ROSTER_MAX_AGE_MS = 60 * 6e4;
1030
+ var ROSTER_CONTEXT = "byollm/v1/roster";
1031
+ var SignedRoster = z8.object({
1032
+ /** Whose devices this roster governs. */
1033
+ owner: z8.string().min(1),
1034
+ /**
1035
+ * Who may have their `team` work run on this owner's devices.
1036
+ *
1037
+ * Owner ids, sorted, so the same membership always produces the same
1038
+ * bytes — a document that differed by iteration order would produce a new
1039
+ * signature every read and no way to tell a change from a shuffle.
1040
+ */
1041
+ members: z8.array(z8.string().min(1)),
1042
+ /**
1043
+ * When the control plane signed it — epoch ms, and the **only** honest
1044
+ * anchor for age.
1045
+ *
1046
+ * Not when the daemon received it. A relay that simply withholds updates
1047
+ * would otherwise keep a removed member served forever, which is the
1048
+ * attack {@link ROSTER_MAX_AGE_MS} exists to bound.
1049
+ */
1050
+ issuedAt: z8.number().int().positive(),
1051
+ /** Base64url Ed25519 over {@link rosterStatement}. */
1052
+ signature: z8.string().min(1)
1053
+ }).strict();
1054
+ function rosterStatement(input) {
1055
+ return Buffer2.from(
1056
+ [
1057
+ ROSTER_CONTEXT,
1058
+ input.owner,
1059
+ String(input.issuedAt),
1060
+ [...input.members].sort().join("\0")
1061
+ ].join("\n"),
1062
+ "utf8"
1063
+ );
1064
+ }
1065
+ function signRoster(keys, input) {
1066
+ const members = [...input.members].sort();
1067
+ return {
1068
+ owner: input.owner,
1069
+ members,
1070
+ issuedAt: input.issuedAt,
1071
+ signature: signWith(keys, rosterStatement({ ...input, members }))
1072
+ };
1073
+ }
1074
+ function verifyRoster(input) {
1075
+ const { roster, owner, now } = input;
1076
+ if (roster.owner !== owner) return "wrong-owner";
1077
+ const age = now - roster.issuedAt;
1078
+ if (age < 0) return "from-the-future";
1079
+ if (age > (input.maxAgeMs ?? ROSTER_MAX_AGE_MS)) return "stale";
1080
+ return verifyWith(
1081
+ input.controlPlanePublic,
1082
+ rosterStatement(roster),
1083
+ roster.signature
1084
+ ) ? null : "bad-signature";
1085
+ }
1086
+
1087
+ // src/succession.ts
1088
+ import { z as z9 } from "zod";
1028
1089
  var SUCCESSION_CONTEXT = "byollm/v1/site-succession";
1029
1090
  var RETIREMENT_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
1030
1091
  var MAX_SUCCESSION_CHAIN = 64;
1031
- var Succession = z8.object({
1092
+ var Succession = z9.object({
1032
1093
  /**
1033
1094
  * The predecessor's public identity — K1, in full.
1034
1095
  *
@@ -1038,7 +1099,7 @@ var Succession = z8.object({
1038
1099
  */
1039
1100
  identity: PublicIdentity,
1040
1101
  /** K1's signature over the statement naming K1 and its successor. */
1041
- signature: z8.string().min(1)
1102
+ signature: z9.string().min(1)
1042
1103
  }).strict();
1043
1104
  function successionStatement(fromKeyId, toKeyId) {
1044
1105
  return Buffer.from(`${SUCCESSION_CONTEXT}:${fromKeyId}:${toKeyId}`);
@@ -1517,7 +1578,7 @@ function mustsVerifiedBy(kind) {
1517
1578
  }
1518
1579
 
1519
1580
  // src/wire.ts
1520
- import { z as z9 } from "zod";
1581
+ import { z as z10 } from "zod";
1521
1582
  var PROTOCOL_VERSION = "0";
1522
1583
  var SUPPORTED_PROTOCOL_VERSIONS = Object.freeze([
1523
1584
  PROTOCOL_VERSION
@@ -1560,7 +1621,7 @@ var ENDPOINTS = Object.freeze([
1560
1621
  "result",
1561
1622
  "release"
1562
1623
  ]);
1563
- var Capability = z9.object({
1624
+ var Capability = z10.object({
1564
1625
  kind: JobKind,
1565
1626
  /**
1566
1627
  * The owner's name for the service answering this kind — byollm_016.
@@ -1569,7 +1630,7 @@ var Capability = z9.object({
1569
1630
  * that something does. Phase B lets a job select by this name; until then
1570
1631
  * it is what a device page shows and what a default is chosen between.
1571
1632
  */
1572
- service: z9.string().min(1),
1633
+ service: z10.string().min(1),
1573
1634
  /**
1574
1635
  * Whether this row is the default for its kind.
1575
1636
  *
@@ -1579,27 +1640,27 @@ var Capability = z9.object({
1579
1640
  * alone" would have to unlearn it, and the ones that did not would be
1580
1641
  * quietly wrong. One field now, no second shape later.
1581
1642
  */
1582
- isDefault: z9.boolean(),
1643
+ isDefault: z10.boolean(),
1583
1644
  backendId: BackendIdSchema,
1584
1645
  backendClass: BackendClass,
1585
- model: z9.string().min(1),
1646
+ model: z10.string().min(1),
1586
1647
  offerScope: OfferScope
1587
1648
  }).strict();
1588
- var CapabilityMatrix = z9.array(Capability);
1589
- var WithheldKind = z9.object({
1649
+ var CapabilityMatrix = z10.array(Capability);
1650
+ var WithheldKind = z10.object({
1590
1651
  kind: JobKind,
1591
- claimants: z9.array(
1592
- z9.object({ service: z9.string().min(1), offer: OfferScope }).strict()
1652
+ claimants: z10.array(
1653
+ z10.object({ service: z10.string().min(1), offer: OfferScope }).strict()
1593
1654
  ).min(2)
1594
1655
  }).strict();
1595
- var PairStartRequest = z9.object({
1596
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1597
- action: z9.literal("start"),
1598
- daemon: z9.object({
1599
- version: z9.string().min(1),
1656
+ var PairStartRequest = z10.object({
1657
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
1658
+ action: z10.literal("start"),
1659
+ daemon: z10.object({
1660
+ version: z10.string().min(1),
1600
1661
  /** Shown in the app's runner list so a user can tell their machines apart. */
1601
- label: z9.string().min(1).max(120),
1602
- platform: z9.enum(["darwin", "linux", "win32"])
1662
+ label: z10.string().min(1).max(120),
1663
+ platform: z10.enum(["darwin", "linux", "win32"])
1603
1664
  }),
1604
1665
  /**
1605
1666
  * This machine's public keys (byollm_009 §5).
@@ -1611,29 +1672,29 @@ var PairStartRequest = z9.object({
1611
1672
  device: PublicIdentity,
1612
1673
  capabilities: CapabilityMatrix
1613
1674
  }).strict();
1614
- var PairStartResponse = z9.object({
1675
+ var PairStartResponse = z10.object({
1615
1676
  /** Secret the daemon polls with. Never shown to the user. */
1616
- deviceCode: z9.string().min(20),
1677
+ deviceCode: z10.string().min(20),
1617
1678
  /** Short code the user reads and confirms in the browser. */
1618
- userCode: z9.string().min(4).max(16),
1679
+ userCode: z10.string().min(4).max(16),
1619
1680
  /** Where the user approves. Must be on the server's own origin. */
1620
- verificationUrl: z9.url(),
1681
+ verificationUrl: z10.url(),
1621
1682
  /** Epoch ms after which the code is dead ({@link MUSTS.PAIR_CODE_EXPIRES}). */
1622
- expiresAt: z9.number().int().positive(),
1683
+ expiresAt: z10.number().int().positive(),
1623
1684
  /** How often the daemon may poll. */
1624
- pollIntervalMs: z9.number().int().min(500).max(6e4)
1685
+ pollIntervalMs: z10.number().int().min(500).max(6e4)
1625
1686
  }).strict();
1626
- var PairPollRequest = z9.object({
1627
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1628
- action: z9.literal("poll"),
1629
- deviceCode: z9.string().min(20)
1687
+ var PairPollRequest = z10.object({
1688
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
1689
+ action: z10.literal("poll"),
1690
+ deviceCode: z10.string().min(20)
1630
1691
  }).strict();
1631
- var PairPollResponse = z9.discriminatedUnion("status", [
1632
- z9.object({ status: z9.literal("pending") }).strict(),
1633
- z9.object({ status: z9.literal("denied") }).strict(),
1634
- z9.object({ status: z9.literal("expired") }).strict(),
1635
- z9.object({
1636
- status: z9.literal("approved"),
1692
+ var PairPollResponse = z10.discriminatedUnion("status", [
1693
+ z10.object({ status: z10.literal("pending") }).strict(),
1694
+ z10.object({ status: z10.literal("denied") }).strict(),
1695
+ z10.object({ status: z10.literal("expired") }).strict(),
1696
+ z10.object({
1697
+ status: z10.literal("approved"),
1637
1698
  // `runnerToken` is gone — cloud_008 §2.4, finding 37.
1638
1699
  //
1639
1700
  // It was minted here, hashed into `RunnerRecord.tokenHash`, written to
@@ -1650,11 +1711,11 @@ var PairPollResponse = z9.discriminatedUnion("status", [
1650
1711
  // `REQUESTS_SIGNED_NOT_BEARER` was already the rule and was already
1651
1712
  // enforced — every authenticated call is signed by the device's pinned
1652
1713
  // identity key. This removes the thing the MUST is named after.
1653
- runnerId: z9.string().min(1),
1714
+ runnerId: z10.string().min(1),
1654
1715
  /** The app's id for the approving user — this daemon's owner forever. */
1655
- owner: z9.string().min(1),
1716
+ owner: z10.string().min(1),
1656
1717
  /** Display name for the trust UI, if the app offers one. */
1657
- ownerLabel: z9.string().optional(),
1718
+ ownerLabel: z10.string().optional(),
1658
1719
  /**
1659
1720
  * The sites this pairing covers, for the daemon to pin (byollm_009 §5),
1660
1721
  * keyed by each site's identity key id — cloud_009 §5.
@@ -1673,34 +1734,55 @@ var PairPollResponse = z9.discriminatedUnion("status", [
1673
1734
  * runner's lookup is a map read rather than a join across two
1674
1735
  * namespaces.
1675
1736
  */
1676
- sites: z9.record(z9.string().min(1), PublicIdentity)
1737
+ sites: z10.record(z10.string().min(1), PublicIdentity),
1738
+ /**
1739
+ * The control plane's roster-signing key, pinned here — Amendment G.
1740
+ *
1741
+ * **Pairing is when, and that is the whole question.** Pairing is
1742
+ * already the ceremony where an owner proves out of band that this
1743
+ * device is theirs, so a key learned here rides trust that has already
1744
+ * happened. The rejected alternative is trust-on-first-roster, and it
1745
+ * is rejected because it hands the decision back to the relay: a daemon
1746
+ * that learns whose signature to trust from the first roster to arrive
1747
+ * has its membership authority chosen by whoever controls delivery.
1748
+ *
1749
+ * Optional on the wire, and only on the wire: a direct-mode server has
1750
+ * no control plane and signs no rosters, and a daemon that never
1751
+ * receives one simply serves no `team` job through it. It is not
1752
+ * optional for a hub — a hub that omitted it would be asking devices to
1753
+ * accept rosters from nobody in particular.
1754
+ *
1755
+ * Rotation is Amendment C's, with no path where a roster teaches a
1756
+ * daemon a new key.
1757
+ */
1758
+ controlPlanePublic: z10.string().min(1).optional()
1677
1759
  }).strict()
1678
1760
  ]);
1679
- var PairRequest = z9.discriminatedUnion("action", [
1761
+ var PairRequest = z10.discriminatedUnion("action", [
1680
1762
  PairStartRequest,
1681
1763
  PairPollRequest
1682
1764
  ]);
1683
- var ClaimRequest = z9.object({
1684
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1685
- runnerId: z9.string().min(1),
1765
+ var ClaimRequest = z10.object({
1766
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
1767
+ runnerId: z10.string().min(1),
1686
1768
  /** Re-sent on every claim so a server never matches against a stale matrix. */
1687
1769
  capabilities: CapabilityMatrix,
1688
1770
  /** Upper bound on jobs to return; the server may return fewer. */
1689
- max: z9.number().int().min(1).max(64)
1771
+ max: z10.number().int().min(1).max(64)
1690
1772
  }).strict();
1691
- var ClaimResponse = z9.object({
1773
+ var ClaimResponse = z10.object({
1692
1774
  /**
1693
1775
  * Stubs, not jobs. The payload arrives from `fetch`, sealed to whichever
1694
1776
  * device claimed — see {@link JobStub} for the exhaustive metadata list.
1695
1777
  */
1696
- jobs: z9.array(ClaimedStub),
1778
+ jobs: z10.array(ClaimedStub),
1697
1779
  /** Lease duration granted, so the daemon knows its renewal deadline. */
1698
- leaseMs: z9.number().int().positive()
1780
+ leaseMs: z10.number().int().positive()
1699
1781
  }).strict();
1700
- var HeartbeatRequest = z9.object({
1701
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1702
- runnerId: z9.string().min(1),
1703
- daemonVersion: z9.string().min(1),
1782
+ var HeartbeatRequest = z10.object({
1783
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
1784
+ runnerId: z10.string().min(1),
1785
+ daemonVersion: z10.string().min(1),
1704
1786
  capabilities: CapabilityMatrix,
1705
1787
  /**
1706
1788
  * Kinds this device is withholding, and why it can be said.
@@ -1709,20 +1791,20 @@ var HeartbeatRequest = z9.object({
1709
1791
  * older daemon against a newer hub is simply a device with no withheld
1710
1792
  * kinds rather than a parse failure.
1711
1793
  */
1712
- withheld: z9.array(WithheldKind).default([]),
1794
+ withheld: z10.array(WithheldKind).default([]),
1713
1795
  /**
1714
1796
  * Leases this daemon believes it holds; the server renews exactly these.
1715
1797
  *
1716
1798
  * Lease ids rather than job ids, so a replayed heartbeat cannot renew a
1717
1799
  * grant the runner no longer holds — see {@link Lease.id}.
1718
1800
  */
1719
- activeLeases: z9.array(
1720
- z9.object({ jobId: z9.string().min(1), leaseId: z9.string().min(1) })
1801
+ activeLeases: z10.array(
1802
+ z10.object({ jobId: z10.string().min(1), leaseId: z10.string().min(1) })
1721
1803
  ),
1722
1804
  /** True while the owner has the daemon paused; the server stops offering work. */
1723
- paused: z9.boolean()
1805
+ paused: z10.boolean()
1724
1806
  }).strict();
1725
- var HeartbeatResponse = z9.object({
1807
+ var HeartbeatResponse = z10.object({
1726
1808
  /**
1727
1809
  * The sites this daemon may serve, right now — cloud_008 finding 59.
1728
1810
  *
@@ -1740,7 +1822,7 @@ var HeartbeatResponse = z9.object({
1740
1822
  * rather than being told a second time — two fields for one fact is how
1741
1823
  * they drift.
1742
1824
  */
1743
- sites: z9.record(z9.string().min(1), PublicIdentity),
1825
+ sites: z10.record(z10.string().min(1), PublicIdentity),
1744
1826
  /**
1745
1827
  * How a site's current key traces back to one this daemon already holds —
1746
1828
  * byollm_009 Amendment C.
@@ -1758,11 +1840,11 @@ var HeartbeatResponse = z9.object({
1758
1840
  * history is public by construction, because a daemon that cannot read it
1759
1841
  * cannot verify it.
1760
1842
  */
1761
- successions: z9.record(
1762
- z9.string().min(1),
1763
- z9.object({
1843
+ successions: z10.record(
1844
+ z10.string().min(1),
1845
+ z10.object({
1764
1846
  /** Oldest last, as the projection carries it. */
1765
- succeeds: z9.array(Succession).max(MAX_SUCCESSION_CHAIN),
1847
+ succeeds: z10.array(Succession).max(MAX_SUCCESSION_CHAIN),
1766
1848
  /**
1767
1849
  * Until when the superseded key may still sign work — epoch ms.
1768
1850
  *
@@ -1771,7 +1853,7 @@ var HeartbeatResponse = z9.object({
1771
1853
  * window indefinitely would be a two-key site forever, decided by
1772
1854
  * the party this design does not trust.
1773
1855
  */
1774
- retiringUntil: z9.number().int().positive().optional()
1856
+ retiringUntil: z10.number().int().positive().optional()
1775
1857
  }).strict()
1776
1858
  ).optional(),
1777
1859
  /**
@@ -1784,8 +1866,8 @@ var HeartbeatResponse = z9.object({
1784
1866
  * is the unique grant and the daemon already keys its work by it; this is
1785
1867
  * the same shape `activeLeases` sends in the other direction.
1786
1868
  */
1787
- cancel: z9.array(
1788
- z9.object({ jobId: z9.string().min(1), leaseId: z9.string().min(1) }).strict()
1869
+ cancel: z10.array(
1870
+ z10.object({ jobId: z10.string().min(1), leaseId: z10.string().min(1) }).strict()
1789
1871
  ),
1790
1872
  // `leases` is deliberately absent — cloud_008 §1.4b, finding 16.
1791
1873
  //
@@ -1815,11 +1897,11 @@ var HeartbeatResponse = z9.object({
1815
1897
  * ambiguous across sites, and "the lease you no longer hold" is exactly
1816
1898
  * what this field means anyway.
1817
1899
  */
1818
- lost: z9.array(
1819
- z9.object({ jobId: z9.string().min(1), leaseId: z9.string().min(1) }).strict()
1900
+ lost: z10.array(
1901
+ z10.object({ jobId: z10.string().min(1), leaseId: z10.string().min(1) }).strict()
1820
1902
  ),
1821
1903
  /** Server clock, so a daemon with a skewed clock still honors leases. */
1822
- serverTime: z9.number().int().positive(),
1904
+ serverTime: z10.number().int().positive(),
1823
1905
  /**
1824
1906
  * Sites whose disclosure the user must read again before work moves —
1825
1907
  * cloud_008 finding 48, named rather than counted.
@@ -1834,13 +1916,28 @@ var HeartbeatResponse = z9.object({
1834
1916
  * operator stopped it" — one word with two subjects on two halves of one
1835
1917
  * exchange is a confusion nobody untangles from a log.
1836
1918
  */
1837
- awaitingConsent: z9.array(z9.string().min(1))
1919
+ awaitingConsent: z10.array(z10.string().min(1)),
1920
+ /**
1921
+ * Who this owner's devices may serve `team` work for — Amendment G.
1922
+ *
1923
+ * Carried by the relay and authored by nobody it can reach. The daemon
1924
+ * verifies it against the key pinned at pairing and admits from its own
1925
+ * held copy, so this field is delivery and not instruction: withholding
1926
+ * it narrows a device, and editing it is caught.
1927
+ *
1928
+ * Optional because a roster is a cloud-mode fact — direct mode has no
1929
+ * control plane to author one — and because a daemon that has never
1930
+ * received one must narrow rather than fail. Absent is not "admit
1931
+ * nobody"; {@link ROSTER_MAX_AGE_MS} is what makes absence bite, and it
1932
+ * bites the same way for a roster withheld as for one never sent.
1933
+ */
1934
+ roster: SignedRoster.optional()
1838
1935
  }).strict();
1839
- var ResultDisposition = z9.enum(["ok", "error", "canceled"]);
1840
- var ResultRequest = z9.object({
1841
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1842
- runnerId: z9.string().min(1),
1843
- jobId: z9.string().min(1),
1936
+ var ResultDisposition = z10.enum(["ok", "error", "canceled"]);
1937
+ var ResultRequest = z10.object({
1938
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
1939
+ runnerId: z10.string().min(1),
1940
+ jobId: z10.string().min(1),
1844
1941
  /**
1845
1942
  * The grant this result was produced under — cloud_008 §1.4a.
1846
1943
  *
@@ -1863,7 +1960,7 @@ var ResultRequest = z9.object({
1863
1960
  * learned once already, when a replayed release yanked a later grant, and
1864
1961
  * it applies here for the same reason.
1865
1962
  */
1866
- leaseId: z9.string().min(1),
1963
+ leaseId: z10.string().min(1),
1867
1964
  /**
1868
1965
  * The outcome, sealed to the site and signed by the device.
1869
1966
  *
@@ -1895,12 +1992,12 @@ var ResultRequest = z9.object({
1895
1992
  // on it, so it is a class a routing party consumes. Nobody between the
1896
1993
  // two ends consumes these.
1897
1994
  }).strict();
1898
- var ResultResponse = z9.object({
1995
+ var ResultResponse = z10.object({
1899
1996
  /**
1900
1997
  * False when this submission wrote nothing — the daemon should discard,
1901
1998
  * not retry ({@link MUSTS.RESULT_IDEMPOTENT}).
1902
1999
  */
1903
- accepted: z9.boolean(),
2000
+ accepted: z10.boolean(),
1904
2001
  /**
1905
2002
  * True when this device had already recorded this job's result.
1906
2003
  *
@@ -1914,13 +2011,13 @@ var ResultResponse = z9.object({
1914
2011
  * the same refusal it would get for a job that is *not* terminal, so a job
1915
2012
  * id cannot be used as a terminality probe.
1916
2013
  */
1917
- duplicate: z9.boolean().optional(),
2014
+ duplicate: z10.boolean().optional(),
1918
2015
  /** The job's state after this submission. */
1919
- state: z9.string().min(1)
2016
+ state: z10.string().min(1)
1920
2017
  }).strict();
1921
- var ReleaseRequest = z9.object({
1922
- protocolVersion: z9.literal(PROTOCOL_VERSION),
1923
- runnerId: z9.string().min(1),
2018
+ var ReleaseRequest = z10.object({
2019
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
2020
+ runnerId: z10.string().min(1),
1924
2021
  /**
1925
2022
  * Which leases to release — the grant, not just the job.
1926
2023
  *
@@ -1928,8 +2025,8 @@ var ReleaseRequest = z9.object({
1928
2025
  * moment it arrives, which for a replayed request is not the lease the
1929
2026
  * daemon meant. See {@link Lease.id}.
1930
2027
  */
1931
- leases: z9.array(
1932
- z9.object({ jobId: z9.string().min(1), leaseId: z9.string().min(1) })
2028
+ leases: z10.array(
2029
+ z10.object({ jobId: z10.string().min(1), leaseId: z10.string().min(1) })
1933
2030
  ),
1934
2031
  /**
1935
2032
  * Why, so the app's runner list can say something true.
@@ -1940,12 +2037,12 @@ var ReleaseRequest = z9.object({
1940
2037
  * stop offering that job to that runner, or the pair would spin between
1941
2038
  * claim and release forever.
1942
2039
  */
1943
- reason: z9.enum(["shutdown", "pause", "revoked", "backend-down", "refused"])
2040
+ reason: z10.enum(["shutdown", "pause", "revoked", "backend-down", "refused"])
1944
2041
  }).strict();
1945
- var ReleaseResponse = z9.object({
1946
- released: z9.array(z9.string().min(1))
2042
+ var ReleaseResponse = z10.object({
2043
+ released: z10.array(z10.string().min(1))
1947
2044
  }).strict();
1948
- var WireErrorCode = z9.enum([
2045
+ var WireErrorCode = z10.enum([
1949
2046
  "bad-request",
1950
2047
  "unsupported-protocol-version",
1951
2048
  // "We do not know who you are." Exactly 401, and only that — cloud_008
@@ -1995,9 +2092,9 @@ var WireErrorCode = z9.enum([
1995
2092
  "rate-limited",
1996
2093
  "server-error"
1997
2094
  ]);
1998
- var WireError = z9.object({
2095
+ var WireError = z10.object({
1999
2096
  error: WireErrorCode,
2000
- message: z9.string().min(1),
2097
+ message: z10.string().min(1),
2001
2098
  /**
2002
2099
  * What this server speaks, on `unsupported-protocol-version` — §B.4.
2003
2100
  *
@@ -2011,10 +2108,10 @@ var WireError = z9.object({
2011
2108
  * Modelled the way `clock-skew`'s two fields already are — code-specific
2012
2109
  * extras, refused on any other code by the refinement below.
2013
2110
  */
2014
- supported: z9.array(z9.string().min(1)).optional(),
2015
- minimum: z9.string().min(1).optional(),
2111
+ supported: z10.array(z10.string().min(1)).optional(),
2112
+ minimum: z10.string().min(1).optional(),
2016
2113
  /** Seconds; mirrors Retry-After for `rate-limited` and `server-error`. */
2017
- retryAfter: z9.number().int().nonnegative().optional(),
2114
+ retryAfter: z10.number().int().nonnegative().optional(),
2018
2115
  /**
2019
2116
  * The server's clock, and the window it allows. `clock-skew` only.
2020
2117
  *
@@ -2024,8 +2121,8 @@ var WireError = z9.object({
2024
2121
  * heartbeat response returns the same value, and so does every `Date`
2025
2122
  * header.
2026
2123
  */
2027
- serverTime: z9.number().int().positive().optional(),
2028
- maxSkewMs: z9.number().int().positive().optional()
2124
+ serverTime: z10.number().int().positive().optional(),
2125
+ maxSkewMs: z10.number().int().positive().optional()
2029
2126
  }).strict().superRefine((error, ctx) => {
2030
2127
  const skew = error.error === "clock-skew";
2031
2128
  const carried = error.serverTime !== void 0 || error.maxSkewMs !== void 0;
@@ -2076,16 +2173,16 @@ var ERROR_STATUS = Object.freeze({
2076
2173
  "rate-limited": 429,
2077
2174
  "server-error": 500
2078
2175
  });
2079
- var FetchRequest = z9.object({
2176
+ var FetchRequest = z10.object({
2080
2177
  // `literal`, like every other request — V1-17. This one said
2081
2178
  // `string().min(1)`, so a daemon speaking a version this server does not
2082
2179
  // know got past the handshake on the one endpoint that hands over a
2083
2180
  // sealed payload. The version check exists so that a mismatch is a named
2084
2181
  // refusal rather than a schema failure three fields later; here it was
2085
2182
  // neither.
2086
- protocolVersion: z9.literal(PROTOCOL_VERSION),
2087
- runnerId: z9.string().min(1),
2088
- jobId: z9.string().min(1),
2183
+ protocolVersion: z10.literal(PROTOCOL_VERSION),
2184
+ runnerId: z10.string().min(1),
2185
+ jobId: z10.string().min(1),
2089
2186
  /**
2090
2187
  * The grant this daemon holds.
2091
2188
  *
@@ -2093,9 +2190,9 @@ var FetchRequest = z9.object({
2093
2190
  * only the job would be answerable for whatever lease exists when it
2094
2191
  * arrives ({@link Lease.id}).
2095
2192
  */
2096
- leaseId: z9.string().min(1)
2193
+ leaseId: z10.string().min(1)
2097
2194
  }).strict();
2098
- var FetchResponse = z9.object({
2195
+ var FetchResponse = z10.object({
2099
2196
  /**
2100
2197
  * The work, sealed to the device that claimed it — byollm_009 §6.
2101
2198
  *
@@ -2164,6 +2261,8 @@ export {
2164
2261
  PublicIdentity,
2165
2262
  REFUSAL_MESSAGES,
2166
2263
  RETIREMENT_WINDOW_MS,
2264
+ ROSTER_CONTEXT,
2265
+ ROSTER_MAX_AGE_MS,
2167
2266
  RefusalReason,
2168
2267
  ReleaseRequest,
2169
2268
  ReleaseResponse,
@@ -2178,6 +2277,7 @@ export {
2178
2277
  SUPPORTED_PROTOCOL_VERSIONS,
2179
2278
  SealedEnvelope,
2180
2279
  SealedOutcome,
2280
+ SignedRoster,
2181
2281
  SizeClass,
2182
2282
  StoredKeys,
2183
2283
  Succession,
@@ -2210,8 +2310,10 @@ export {
2210
2310
  provenanceFor,
2211
2311
  publicIdentityOf,
2212
2312
  resolveCost,
2313
+ rosterStatement,
2213
2314
  seal,
2214
2315
  signRequest,
2316
+ signRoster,
2215
2317
  signSiteRequest,
2216
2318
  signSuccession,
2217
2319
  signWith,
@@ -2221,6 +2323,7 @@ export {
2221
2323
  verifyLink,
2222
2324
  verifyPublicIdentity,
2223
2325
  verifyRequest,
2326
+ verifyRoster,
2224
2327
  verifySiteRequest,
2225
2328
  verifyWith,
2226
2329
  walkSuccession