@byollm/protocol 0.1.0-alpha.43 → 0.1.0-alpha.44
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/README.md +6 -6
- package/dist/index.d.ts +151 -43
- package/dist/index.js +52 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
> [!WARNING]
|
|
2
|
-
> **Alpha (`0.1.0-alpha.
|
|
2
|
+
> **Alpha (`0.1.0-alpha.44`) — under active development. Don't use this yet.**
|
|
3
3
|
>
|
|
4
4
|
> Install it deliberately: `npm install @byollm/protocol@alpha`.
|
|
5
5
|
>
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
> packages published and `@byollm/server` did not: a Sigstore
|
|
84
84
|
> transparency-log 409 on its provenance attestation. The workflow's
|
|
85
85
|
> "already published" guard correctly refuses to resume a partial publish,
|
|
86
|
-
> so `0.1.0-alpha.
|
|
86
|
+
> so `0.1.0-alpha.44` is that release, whole.
|
|
87
87
|
>
|
|
88
88
|
> If you run the Supabase adapter, `alpha.21` needs
|
|
89
89
|
> `20260819010000_completed_by_lease_id.sql`: alpha.19 shipped §3.6's
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
<!-- release-note 0.1.0-alpha.40 -->
|
|
93
93
|
**`byollm install` — stop keeping a terminal open.** The daemon can now run
|
|
94
|
-
under your
|
|
94
|
+
under your computer's own supervisor and restart itself if it stops: a launchd
|
|
95
95
|
agent on macOS, a `systemd --user` unit on Linux, a logon task on Windows. All
|
|
96
96
|
user-level — no root, no system directories, and `byollm uninstall` takes it
|
|
97
97
|
away. `byollm status` gained a line saying whether it is actually supervised
|
|
@@ -115,7 +115,7 @@ const { outcome, fallback } = await job.result({
|
|
|
115
115
|
|
|
116
116
|
Whatever you return, `result()` labels it `fallback: true` — the stamp is
|
|
117
117
|
applied by the wait, not taken from you, so an answer that did not run on
|
|
118
|
-
somebody's
|
|
118
|
+
somebody's device cannot be reported as though it did (`FALLBACK_LABELED`).
|
|
119
119
|
Both delivery channels do it, polling and Supabase Realtime. Records still
|
|
120
120
|
work; they just get labelled too.
|
|
121
121
|
|
|
@@ -166,10 +166,10 @@ job's owner.
|
|
|
166
166
|
import { matchAudience } from "@byollm/protocol";
|
|
167
167
|
|
|
168
168
|
matchAudience(
|
|
169
|
-
{ owner: "alice", audience: "
|
|
169
|
+
{ owner: "alice", audience: "team" },
|
|
170
170
|
{
|
|
171
171
|
owner: "bob",
|
|
172
|
-
offerScope: "
|
|
172
|
+
offerScope: "team",
|
|
173
173
|
account: "open",
|
|
174
174
|
// The daemon's OWN allowlist decides — never the server's assertion.
|
|
175
175
|
locallyAllows: (owner) => owner === "alice",
|
package/dist/index.d.ts
CHANGED
|
@@ -157,45 +157,98 @@ declare function backendDescriptor(id: BackendId): BackendDescriptor;
|
|
|
157
157
|
*/
|
|
158
158
|
declare function isLocalHost(hostname: string): boolean;
|
|
159
159
|
/**
|
|
160
|
-
*
|
|
160
|
+
* Is this model name a hosted one billed by its vendor?
|
|
161
|
+
*
|
|
162
|
+
* Ollama serves cloud models through the same local endpoint as local ones,
|
|
163
|
+
* so the address says "free" about a model somebody is being charged for. The
|
|
164
|
+
* only thing that distinguishes them is the name, and the distinguishing part
|
|
165
|
+
* is the **tag** — everything after the last colon.
|
|
166
|
+
*
|
|
167
|
+
* End-anchored on the tag, which is what makes it decidable rather than a
|
|
168
|
+
* guess about substrings:
|
|
169
|
+
*
|
|
170
|
+
* - `glm-5.2:cloud` → cloud
|
|
171
|
+
* - `deepseek-v4-flash:0731-cloud` → cloud
|
|
172
|
+
* - `x:cloudless` → not cloud, the tag ends in "less"
|
|
173
|
+
* - `cloudmodel:7b` → not cloud, the tag is "7b"
|
|
174
|
+
* - `llama3.2` → not cloud, there is no tag at all
|
|
175
|
+
*
|
|
176
|
+
* An oddball like `:xcloud` classifies as cloud, and that is the **only
|
|
177
|
+
* permitted failure direction**: calling a free model metered narrows what an
|
|
178
|
+
* owner may share and costs nobody money, while the reverse hands somebody
|
|
179
|
+
* else's bill to a stranger.
|
|
180
|
+
*/
|
|
181
|
+
declare function isCloudTaggedModel(model: string): boolean;
|
|
182
|
+
/**
|
|
183
|
+
* The cost class of a configured service.
|
|
161
184
|
*
|
|
162
185
|
* For every named provider this is whatever the registry says, full stop
|
|
163
186
|
* ({@link MUSTS.COST_NOT_CONFIGURABLE}). For the generic `openai-http` entry
|
|
164
187
|
* it is inferred from the base URL, and a base URL that cannot be parsed is
|
|
165
188
|
* treated as `metered` — the expensive side, because guessing "free" wrong
|
|
166
189
|
* costs the owner money.
|
|
190
|
+
*
|
|
191
|
+
* The model has the last word in one direction only. A local address with a
|
|
192
|
+
* cloud-tagged model is `metered`: Ollama proxies hosted models through
|
|
193
|
+
* `127.0.0.1`, so the endpoint is local and the bill is not. Read from the
|
|
194
|
+
* **configured value**, never from what the server lists — the owner's config
|
|
195
|
+
* is the thing they chose, and a server's catalogue is not theirs to be
|
|
196
|
+
* classified by.
|
|
167
197
|
*/
|
|
168
|
-
declare function resolveCost(id: BackendId, baseUrl: string | undefined): BackendCost;
|
|
198
|
+
declare function resolveCost(id: BackendId, baseUrl: string | undefined, model?: string): BackendCost;
|
|
169
199
|
|
|
170
200
|
/**
|
|
171
201
|
* Who may run a job, declared by the app that enqueued it.
|
|
172
202
|
*
|
|
173
|
-
* - `
|
|
174
|
-
* - `
|
|
175
|
-
*
|
|
176
|
-
*
|
|
203
|
+
* - `private` — only the job owner's own devices.
|
|
204
|
+
* - `team` — a device whose owner has this person on their roster.
|
|
205
|
+
* - `public` — any device offering `public` compute.
|
|
206
|
+
*
|
|
207
|
+
* **One vocabulary, ruled 2026-08-24.** These were `self | named | public`
|
|
208
|
+
* while {@link OfferScope} became `private | team | public`, which would have
|
|
209
|
+
* left every seam where the two meet speaking two languages for one idea, and
|
|
210
|
+
* every doc explaining "self versus private" for ever. They are still
|
|
211
|
+
* independent axes — a job says who may run it, a service says who it will run
|
|
212
|
+
* for — and a job runs only where both agree
|
|
213
|
+
* ({@link MUSTS.AUDIENCE_BOTH_SIDES}). Sharing the words costs nothing and
|
|
214
|
+
* saves a mapping layer nobody would have enjoyed maintaining.
|
|
177
215
|
*/
|
|
178
216
|
declare const Audience: z.ZodEnum<{
|
|
179
|
-
|
|
180
|
-
|
|
217
|
+
private: "private";
|
|
218
|
+
team: "team";
|
|
181
219
|
public: "public";
|
|
182
220
|
}>;
|
|
183
221
|
type Audience = z.infer<typeof Audience>;
|
|
184
222
|
/**
|
|
185
|
-
* What a
|
|
186
|
-
*
|
|
187
|
-
*
|
|
223
|
+
* What a device's owner is willing to run for other people, per service.
|
|
224
|
+
*
|
|
225
|
+
* - `private` — the owner's own work only.
|
|
226
|
+
* - `team` — the owner's roster. Membership is **central**, not per-person:
|
|
227
|
+
* the device follows the roster rather than holding its own copy of who is
|
|
228
|
+
* in it (byollm_016, 2026-08-24).
|
|
229
|
+
* - `public` — any job, from anyone. This is the community posture the daemon
|
|
230
|
+
* has always had (`byollm offer <service> public`), bounded by community
|
|
231
|
+
* budgets. byollm_016 parks it as a **hosted-product** surface — the cloud
|
|
232
|
+
* dashboard does not offer it — which is not the same as removing it from
|
|
233
|
+
* the daemon, and the CLI still accepts it.
|
|
234
|
+
*
|
|
235
|
+
* Deliberately *not* the same words as {@link Audience}, which they used to
|
|
236
|
+
* share. They are independent axes — a job says who may run it, a service says
|
|
237
|
+
* who it will run for — and identical spellings made that read as one concept
|
|
238
|
+
* with two homes. A job runs only where both agree
|
|
239
|
+
* ({@link MUSTS.AUDIENCE_BOTH_SIDES}); {@link matches} is the one place the
|
|
240
|
+
* correspondence lives.
|
|
188
241
|
*/
|
|
189
242
|
declare const OfferScope: z.ZodEnum<{
|
|
190
|
-
|
|
191
|
-
|
|
243
|
+
private: "private";
|
|
244
|
+
team: "team";
|
|
192
245
|
public: "public";
|
|
193
246
|
}>;
|
|
194
247
|
type OfferScope = z.infer<typeof OfferScope>;
|
|
195
248
|
/** All audience values, in widening order. */
|
|
196
|
-
declare const AUDIENCES: readonly ("
|
|
249
|
+
declare const AUDIENCES: readonly ("private" | "team" | "public")[];
|
|
197
250
|
/** All offer scopes, in widening order. */
|
|
198
|
-
declare const OFFER_SCOPES: readonly ("
|
|
251
|
+
declare const OFFER_SCOPES: readonly ("private" | "team" | "public")[];
|
|
199
252
|
/**
|
|
200
253
|
* Why a job was refused. Distinct codes because byollm_002 requires that
|
|
201
254
|
* different truths never share a message — "no matching work" and "refused on
|
|
@@ -236,7 +289,7 @@ interface SpendConsent {
|
|
|
236
289
|
*
|
|
237
290
|
* - `subscription` is locked to `self` regardless of config
|
|
238
291
|
* ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}) — someone else's terms.
|
|
239
|
-
* - `metered` narrows to `
|
|
292
|
+
* - `metered` narrows to `private` unless the owner has explicitly acknowledged
|
|
240
293
|
* the spend ({@link MUSTS.METERED_DEFAULTS_SELF}) — their money.
|
|
241
294
|
* - `free` passes through — their electricity.
|
|
242
295
|
*
|
|
@@ -291,10 +344,10 @@ interface MatchDaemon {
|
|
|
291
344
|
* @example
|
|
292
345
|
* ```ts
|
|
293
346
|
* const result = matchAudience(
|
|
294
|
-
* { owner: "alice", audience: "
|
|
347
|
+
* { owner: "alice", audience: "team" },
|
|
295
348
|
* {
|
|
296
349
|
* owner: "bob",
|
|
297
|
-
* offerScope: "
|
|
350
|
+
* offerScope: "team",
|
|
298
351
|
* cost: "free",
|
|
299
352
|
* locallyAllows: (o) => o === "alice",
|
|
300
353
|
* },
|
|
@@ -505,8 +558,8 @@ declare const ClaimedJob: z.ZodObject<{
|
|
|
505
558
|
system: z.ZodOptional<z.ZodString>;
|
|
506
559
|
}, z.core.$strict>]>;
|
|
507
560
|
audience: z.ZodEnum<{
|
|
508
|
-
|
|
509
|
-
|
|
561
|
+
private: "private";
|
|
562
|
+
team: "team";
|
|
510
563
|
public: "public";
|
|
511
564
|
}>;
|
|
512
565
|
owner: z.ZodString;
|
|
@@ -527,8 +580,8 @@ type ClaimedJob = z.infer<typeof ClaimedJob>;
|
|
|
527
580
|
*/
|
|
528
581
|
declare const ResultProvenance: z.ZodObject<{
|
|
529
582
|
audience: z.ZodEnum<{
|
|
530
|
-
|
|
531
|
-
|
|
583
|
+
private: "private";
|
|
584
|
+
team: "team";
|
|
532
585
|
public: "public";
|
|
533
586
|
}>;
|
|
534
587
|
runnerId: z.ZodString;
|
|
@@ -663,8 +716,8 @@ declare const DeliveredResult: z.ZodObject<{
|
|
|
663
716
|
}, z.core.$strict>], "outcome">>;
|
|
664
717
|
provenance: z.ZodOptional<z.ZodObject<{
|
|
665
718
|
audience: z.ZodEnum<{
|
|
666
|
-
|
|
667
|
-
|
|
719
|
+
private: "private";
|
|
720
|
+
team: "team";
|
|
668
721
|
public: "public";
|
|
669
722
|
}>;
|
|
670
723
|
runnerId: z.ZodString;
|
|
@@ -742,8 +795,8 @@ declare const JobStub: z.ZodObject<{
|
|
|
742
795
|
owner: z.ZodString;
|
|
743
796
|
site: z.ZodString;
|
|
744
797
|
audience: z.ZodEnum<{
|
|
745
|
-
|
|
746
|
-
|
|
798
|
+
private: "private";
|
|
799
|
+
team: "team";
|
|
747
800
|
public: "public";
|
|
748
801
|
}>;
|
|
749
802
|
sizeClass: z.ZodEnum<{
|
|
@@ -766,8 +819,8 @@ declare const ClaimedStub: z.ZodObject<{
|
|
|
766
819
|
owner: z.ZodString;
|
|
767
820
|
site: z.ZodString;
|
|
768
821
|
audience: z.ZodEnum<{
|
|
769
|
-
|
|
770
|
-
|
|
822
|
+
private: "private";
|
|
823
|
+
team: "team";
|
|
771
824
|
public: "public";
|
|
772
825
|
}>;
|
|
773
826
|
sizeClass: z.ZodEnum<{
|
|
@@ -1452,6 +1505,8 @@ declare const Capability: z.ZodObject<{
|
|
|
1452
1505
|
"llm.generate": "llm.generate";
|
|
1453
1506
|
"llm.chat": "llm.chat";
|
|
1454
1507
|
}>;
|
|
1508
|
+
service: z.ZodString;
|
|
1509
|
+
isDefault: z.ZodBoolean;
|
|
1455
1510
|
backendId: z.ZodEnum<{
|
|
1456
1511
|
ollama: "ollama";
|
|
1457
1512
|
mlx: "mlx";
|
|
@@ -1478,8 +1533,8 @@ declare const Capability: z.ZodObject<{
|
|
|
1478
1533
|
}>;
|
|
1479
1534
|
model: z.ZodString;
|
|
1480
1535
|
offerScope: z.ZodEnum<{
|
|
1481
|
-
|
|
1482
|
-
|
|
1536
|
+
private: "private";
|
|
1537
|
+
team: "team";
|
|
1483
1538
|
public: "public";
|
|
1484
1539
|
}>;
|
|
1485
1540
|
}, z.core.$strict>;
|
|
@@ -1490,6 +1545,8 @@ declare const CapabilityMatrix: z.ZodArray<z.ZodObject<{
|
|
|
1490
1545
|
"llm.generate": "llm.generate";
|
|
1491
1546
|
"llm.chat": "llm.chat";
|
|
1492
1547
|
}>;
|
|
1548
|
+
service: z.ZodString;
|
|
1549
|
+
isDefault: z.ZodBoolean;
|
|
1493
1550
|
backendId: z.ZodEnum<{
|
|
1494
1551
|
ollama: "ollama";
|
|
1495
1552
|
mlx: "mlx";
|
|
@@ -1516,12 +1573,41 @@ declare const CapabilityMatrix: z.ZodArray<z.ZodObject<{
|
|
|
1516
1573
|
}>;
|
|
1517
1574
|
model: z.ZodString;
|
|
1518
1575
|
offerScope: z.ZodEnum<{
|
|
1519
|
-
|
|
1520
|
-
|
|
1576
|
+
private: "private";
|
|
1577
|
+
team: "team";
|
|
1521
1578
|
public: "public";
|
|
1522
1579
|
}>;
|
|
1523
1580
|
}, z.core.$strict>>;
|
|
1524
1581
|
type CapabilityMatrix = z.infer<typeof CapabilityMatrix>;
|
|
1582
|
+
/**
|
|
1583
|
+
* A kind this device could serve and deliberately does not — byollm_016.
|
|
1584
|
+
*
|
|
1585
|
+
* Two services answer one kind and the owner has not said which wins, so the
|
|
1586
|
+
* kind is not advertised. That is correct and, unsaid, invisible: the owner
|
|
1587
|
+
* adds a second service, jobs stop matching, and no surface explains it.
|
|
1588
|
+
*
|
|
1589
|
+
* It travels because the surfaces that must say so are not all on the device.
|
|
1590
|
+
* The owner's card names the claimants; a teammate's card says only that the
|
|
1591
|
+
* owner has a choice to make. Claimant **offer scopes** ride along so the hub
|
|
1592
|
+
* can compute that difference without the device deciding who is asking —
|
|
1593
|
+
* carry for computation, filter for display, the same shape the effective
|
|
1594
|
+
* offer already uses.
|
|
1595
|
+
*/
|
|
1596
|
+
declare const WithheldKind: z.ZodObject<{
|
|
1597
|
+
kind: z.ZodEnum<{
|
|
1598
|
+
"llm.generate": "llm.generate";
|
|
1599
|
+
"llm.chat": "llm.chat";
|
|
1600
|
+
}>;
|
|
1601
|
+
claimants: z.ZodArray<z.ZodObject<{
|
|
1602
|
+
service: z.ZodString;
|
|
1603
|
+
offer: z.ZodEnum<{
|
|
1604
|
+
private: "private";
|
|
1605
|
+
team: "team";
|
|
1606
|
+
public: "public";
|
|
1607
|
+
}>;
|
|
1608
|
+
}, z.core.$strict>>;
|
|
1609
|
+
}, z.core.$strict>;
|
|
1610
|
+
type WithheldKind = z.infer<typeof WithheldKind>;
|
|
1525
1611
|
/**
|
|
1526
1612
|
* Pairing is a device-code exchange, not a pasted secret
|
|
1527
1613
|
* ({@link MUSTS.PAIR_INTERACTIVE}). The daemon starts a pairing, shows the
|
|
@@ -1551,6 +1637,8 @@ declare const PairStartRequest: z.ZodObject<{
|
|
|
1551
1637
|
"llm.generate": "llm.generate";
|
|
1552
1638
|
"llm.chat": "llm.chat";
|
|
1553
1639
|
}>;
|
|
1640
|
+
service: z.ZodString;
|
|
1641
|
+
isDefault: z.ZodBoolean;
|
|
1554
1642
|
backendId: z.ZodEnum<{
|
|
1555
1643
|
ollama: "ollama";
|
|
1556
1644
|
mlx: "mlx";
|
|
@@ -1577,8 +1665,8 @@ declare const PairStartRequest: z.ZodObject<{
|
|
|
1577
1665
|
}>;
|
|
1578
1666
|
model: z.ZodString;
|
|
1579
1667
|
offerScope: z.ZodEnum<{
|
|
1580
|
-
|
|
1581
|
-
|
|
1668
|
+
private: "private";
|
|
1669
|
+
team: "team";
|
|
1582
1670
|
public: "public";
|
|
1583
1671
|
}>;
|
|
1584
1672
|
}, z.core.$strict>>;
|
|
@@ -1638,6 +1726,8 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1638
1726
|
"llm.generate": "llm.generate";
|
|
1639
1727
|
"llm.chat": "llm.chat";
|
|
1640
1728
|
}>;
|
|
1729
|
+
service: z.ZodString;
|
|
1730
|
+
isDefault: z.ZodBoolean;
|
|
1641
1731
|
backendId: z.ZodEnum<{
|
|
1642
1732
|
ollama: "ollama";
|
|
1643
1733
|
mlx: "mlx";
|
|
@@ -1664,8 +1754,8 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1664
1754
|
}>;
|
|
1665
1755
|
model: z.ZodString;
|
|
1666
1756
|
offerScope: z.ZodEnum<{
|
|
1667
|
-
|
|
1668
|
-
|
|
1757
|
+
private: "private";
|
|
1758
|
+
team: "team";
|
|
1669
1759
|
public: "public";
|
|
1670
1760
|
}>;
|
|
1671
1761
|
}, z.core.$strict>>;
|
|
@@ -1683,6 +1773,8 @@ declare const ClaimRequest: z.ZodObject<{
|
|
|
1683
1773
|
"llm.generate": "llm.generate";
|
|
1684
1774
|
"llm.chat": "llm.chat";
|
|
1685
1775
|
}>;
|
|
1776
|
+
service: z.ZodString;
|
|
1777
|
+
isDefault: z.ZodBoolean;
|
|
1686
1778
|
backendId: z.ZodEnum<{
|
|
1687
1779
|
ollama: "ollama";
|
|
1688
1780
|
mlx: "mlx";
|
|
@@ -1709,8 +1801,8 @@ declare const ClaimRequest: z.ZodObject<{
|
|
|
1709
1801
|
}>;
|
|
1710
1802
|
model: z.ZodString;
|
|
1711
1803
|
offerScope: z.ZodEnum<{
|
|
1712
|
-
|
|
1713
|
-
|
|
1804
|
+
private: "private";
|
|
1805
|
+
team: "team";
|
|
1714
1806
|
public: "public";
|
|
1715
1807
|
}>;
|
|
1716
1808
|
}, z.core.$strict>>;
|
|
@@ -1727,8 +1819,8 @@ declare const ClaimResponse: z.ZodObject<{
|
|
|
1727
1819
|
owner: z.ZodString;
|
|
1728
1820
|
site: z.ZodString;
|
|
1729
1821
|
audience: z.ZodEnum<{
|
|
1730
|
-
|
|
1731
|
-
|
|
1822
|
+
private: "private";
|
|
1823
|
+
team: "team";
|
|
1732
1824
|
public: "public";
|
|
1733
1825
|
}>;
|
|
1734
1826
|
sizeClass: z.ZodEnum<{
|
|
@@ -1757,6 +1849,8 @@ declare const HeartbeatRequest: z.ZodObject<{
|
|
|
1757
1849
|
"llm.generate": "llm.generate";
|
|
1758
1850
|
"llm.chat": "llm.chat";
|
|
1759
1851
|
}>;
|
|
1852
|
+
service: z.ZodString;
|
|
1853
|
+
isDefault: z.ZodBoolean;
|
|
1760
1854
|
backendId: z.ZodEnum<{
|
|
1761
1855
|
ollama: "ollama";
|
|
1762
1856
|
mlx: "mlx";
|
|
@@ -1783,11 +1877,25 @@ declare const HeartbeatRequest: z.ZodObject<{
|
|
|
1783
1877
|
}>;
|
|
1784
1878
|
model: z.ZodString;
|
|
1785
1879
|
offerScope: z.ZodEnum<{
|
|
1786
|
-
|
|
1787
|
-
|
|
1880
|
+
private: "private";
|
|
1881
|
+
team: "team";
|
|
1788
1882
|
public: "public";
|
|
1789
1883
|
}>;
|
|
1790
1884
|
}, z.core.$strict>>;
|
|
1885
|
+
withheld: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1886
|
+
kind: z.ZodEnum<{
|
|
1887
|
+
"llm.generate": "llm.generate";
|
|
1888
|
+
"llm.chat": "llm.chat";
|
|
1889
|
+
}>;
|
|
1890
|
+
claimants: z.ZodArray<z.ZodObject<{
|
|
1891
|
+
service: z.ZodString;
|
|
1892
|
+
offer: z.ZodEnum<{
|
|
1893
|
+
private: "private";
|
|
1894
|
+
team: "team";
|
|
1895
|
+
public: "public";
|
|
1896
|
+
}>;
|
|
1897
|
+
}, z.core.$strict>>;
|
|
1898
|
+
}, z.core.$strict>>>;
|
|
1791
1899
|
activeLeases: z.ZodArray<z.ZodObject<{
|
|
1792
1900
|
jobId: z.ZodString;
|
|
1793
1901
|
leaseId: z.ZodString;
|
|
@@ -1957,4 +2065,4 @@ declare const FetchResponse: z.ZodObject<{
|
|
|
1957
2065
|
}, z.core.$strict>;
|
|
1958
2066
|
type FetchResponse = z.infer<typeof FetchResponse>;
|
|
1959
2067
|
|
|
1960
|
-
export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, Capability, CapabilityMatrix, ChatMessage, ChatPayload, ClaimRequest, ClaimResponse, ClaimedJob, ClaimedStub, DeliveredResult, ENCRYPTION_KEY_CONTEXT, ENDPOINTS, ENVELOPE_MAX_AGE_MS, ERROR_STATUS, type Endpoint, type EnvelopeContext, EnvelopeDirection, type EnvelopeFailure, FetchRequest, FetchResponse, GeneratePayload, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, type MatchDaemon, type MatchJob, MatchRefusal, type MatchResult, type Must, type MustEnforcer, type MustId, type MustVerification, type MustVerifiedBy, OFFER_SCOPES, OfferScope, type OpenResult, PAYLOAD_LIMITS, PROTOCOL_PREFIX, PROTOCOL_VERSION, PairPollRequest, PairPollResponse, PairRequest, PairStartRequest, PairStartResponse, type PayloadFor, PublicIdentity, REFUSAL_MESSAGES, RETIREMENT_WINDOW_MS, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, backendDescriptor, canTransition, canonicalRequest, checkProtocolVersion, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, isBackendId, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signRequest, signSiteRequest, signSuccession, signWith, sizeClassCeiling, sizeClassOf, successionStatement, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
|
|
2068
|
+
export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, Capability, CapabilityMatrix, ChatMessage, ChatPayload, ClaimRequest, ClaimResponse, ClaimedJob, ClaimedStub, DeliveredResult, ENCRYPTION_KEY_CONTEXT, ENDPOINTS, ENVELOPE_MAX_AGE_MS, ERROR_STATUS, type Endpoint, type EnvelopeContext, EnvelopeDirection, type EnvelopeFailure, FetchRequest, FetchResponse, GeneratePayload, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, type MatchDaemon, type MatchJob, MatchRefusal, type MatchResult, type Must, type MustEnforcer, type MustId, type MustVerification, type MustVerifiedBy, OFFER_SCOPES, OfferScope, type OpenResult, PAYLOAD_LIMITS, PROTOCOL_PREFIX, PROTOCOL_VERSION, PairPollRequest, PairPollResponse, PairRequest, PairStartRequest, PairStartResponse, type PayloadFor, PublicIdentity, REFUSAL_MESSAGES, RETIREMENT_WINDOW_MS, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, canTransition, canonicalRequest, checkProtocolVersion, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signRequest, signSiteRequest, signSuccession, signWith, sizeClassCeiling, sizeClassOf, successionStatement, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
|
package/dist/index.js
CHANGED
|
@@ -189,9 +189,13 @@ function isLocalHost(hostname) {
|
|
|
189
189
|
if (host.startsWith("192.168.")) return true;
|
|
190
190
|
return /^172\.(1[6-9]|2\d|3[01])\./.test(host);
|
|
191
191
|
}
|
|
192
|
-
function
|
|
192
|
+
function isCloudTaggedModel(model) {
|
|
193
|
+
return /:[^:]*cloud$/.test(model);
|
|
194
|
+
}
|
|
195
|
+
function resolveCost(id, baseUrl, model) {
|
|
193
196
|
const declared = BACKENDS[id].cost;
|
|
194
197
|
if (declared !== null) return declared;
|
|
198
|
+
if (model !== void 0 && isCloudTaggedModel(model)) return "metered";
|
|
195
199
|
if (baseUrl === void 0) return "metered";
|
|
196
200
|
try {
|
|
197
201
|
return isLocalHost(new URL(baseUrl).hostname) ? "free" : "metered";
|
|
@@ -201,8 +205,8 @@ function resolveCost(id, baseUrl) {
|
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
// src/audience.ts
|
|
204
|
-
var Audience = z2.enum(["
|
|
205
|
-
var OfferScope = z2.enum(["
|
|
208
|
+
var Audience = z2.enum(["private", "team", "public"]);
|
|
209
|
+
var OfferScope = z2.enum(["private", "team", "public"]);
|
|
206
210
|
var AUDIENCES = Object.freeze(Audience.options);
|
|
207
211
|
var OFFER_SCOPES = Object.freeze(OfferScope.options);
|
|
208
212
|
var MatchRefusal = z2.enum([
|
|
@@ -226,16 +230,16 @@ var MatchRefusal = z2.enum([
|
|
|
226
230
|
var ALLOWED = Object.freeze({ ok: true });
|
|
227
231
|
var refuse = (refusal) => Object.freeze({ ok: false, refusal });
|
|
228
232
|
function effectiveOfferScope(configured, cost, spend) {
|
|
229
|
-
if (cost === "subscription") return "
|
|
230
|
-
if (cost === "metered" && spend?.acknowledged !== true) return "
|
|
233
|
+
if (cost === "subscription") return "private";
|
|
234
|
+
if (cost === "metered" && spend?.acknowledged !== true) return "private";
|
|
231
235
|
return configured;
|
|
232
236
|
}
|
|
233
237
|
function matchAudience(job, daemon) {
|
|
234
238
|
const sameOwner = job.owner === daemon.owner;
|
|
235
|
-
if (job.audience === "
|
|
239
|
+
if (job.audience === "private" && !sameOwner) {
|
|
236
240
|
return refuse("audience-self-other-owner");
|
|
237
241
|
}
|
|
238
|
-
if (job.audience === "
|
|
242
|
+
if (job.audience === "team" && !sameOwner && job.audienceAllow !== void 0 && !job.audienceAllow.includes(daemon.owner)) {
|
|
239
243
|
return refuse("not-in-server-allowlist");
|
|
240
244
|
}
|
|
241
245
|
const scope = effectiveOfferScope(
|
|
@@ -258,19 +262,19 @@ function matchAudience(job, daemon) {
|
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
switch (scope) {
|
|
261
|
-
case "
|
|
265
|
+
case "private":
|
|
262
266
|
return refuse("offer-scope-too-narrow");
|
|
263
|
-
case "
|
|
267
|
+
case "team":
|
|
264
268
|
return daemon.locallyAllows(job.owner) ? ALLOWED : refuse("not-locally-allowed");
|
|
265
269
|
case "public":
|
|
266
270
|
return ALLOWED;
|
|
267
271
|
}
|
|
268
272
|
}
|
|
269
273
|
var REFUSAL_MESSAGES = Object.freeze({
|
|
270
|
-
"no-capability": "no backend on this
|
|
271
|
-
"audience-self-other-owner": "the job is private to its owner and this
|
|
272
|
-
"not-locally-allowed": "the job's owner is not on this
|
|
273
|
-
"not-in-server-allowlist": "the app restricted this job to named runners and this
|
|
274
|
+
"no-capability": "no backend on this device is configured and healthy for that job kind",
|
|
275
|
+
"audience-self-other-owner": "the job is private to its owner and this device is paired to someone else",
|
|
276
|
+
"not-locally-allowed": "the job's owner is not on this device's allowlist (byollm allow <server> <user>)",
|
|
277
|
+
"not-in-server-allowlist": "the app restricted this job to named runners and this device is not one of them",
|
|
274
278
|
"offer-scope-too-narrow": "this backend is offered to its owner only (byollm offer <backend> named|public to widen)",
|
|
275
279
|
"subscription-self-lock": "subscription-backed models run their owner's work only \u2014 this is a protocol rule, not a setting",
|
|
276
280
|
"metered-no-spend-consent": "this backend bills its owner per token, and they have not agreed to spend it on other people's work",
|
|
@@ -431,7 +435,7 @@ function provenanceFor(input) {
|
|
|
431
435
|
runnerOwner: input.runnerOwner,
|
|
432
436
|
backendClass: input.backendClass,
|
|
433
437
|
model: input.model,
|
|
434
|
-
untrusted: input.audience !== "
|
|
438
|
+
untrusted: input.audience !== "private"
|
|
435
439
|
};
|
|
436
440
|
}
|
|
437
441
|
var RunMetadata = z4.object({
|
|
@@ -1388,12 +1392,36 @@ var ENDPOINTS = Object.freeze([
|
|
|
1388
1392
|
]);
|
|
1389
1393
|
var Capability = z9.object({
|
|
1390
1394
|
kind: JobKind,
|
|
1395
|
+
/**
|
|
1396
|
+
* The owner's name for the service answering this kind — byollm_016.
|
|
1397
|
+
*
|
|
1398
|
+
* A device advertises *which* of its services serves a kind, not merely
|
|
1399
|
+
* that something does. Phase B lets a job select by this name; until then
|
|
1400
|
+
* it is what a device page shows and what a default is chosen between.
|
|
1401
|
+
*/
|
|
1402
|
+
service: z9.string().min(1),
|
|
1403
|
+
/**
|
|
1404
|
+
* Whether this row is the default for its kind.
|
|
1405
|
+
*
|
|
1406
|
+
* Stated rather than inferred from being the only row, which is true in
|
|
1407
|
+
* Phase A and stops being true the moment Phase B advertises every
|
|
1408
|
+
* selectable service per kind. A consumer that learned "default means
|
|
1409
|
+
* alone" would have to unlearn it, and the ones that did not would be
|
|
1410
|
+
* quietly wrong. One field now, no second shape later.
|
|
1411
|
+
*/
|
|
1412
|
+
isDefault: z9.boolean(),
|
|
1391
1413
|
backendId: BackendIdSchema,
|
|
1392
1414
|
backendClass: BackendClass,
|
|
1393
1415
|
model: z9.string().min(1),
|
|
1394
1416
|
offerScope: OfferScope
|
|
1395
1417
|
}).strict();
|
|
1396
1418
|
var CapabilityMatrix = z9.array(Capability);
|
|
1419
|
+
var WithheldKind = z9.object({
|
|
1420
|
+
kind: JobKind,
|
|
1421
|
+
claimants: z9.array(
|
|
1422
|
+
z9.object({ service: z9.string().min(1), offer: OfferScope }).strict()
|
|
1423
|
+
).min(2)
|
|
1424
|
+
}).strict();
|
|
1397
1425
|
var PairStartRequest = z9.object({
|
|
1398
1426
|
protocolVersion: z9.literal(PROTOCOL_VERSION),
|
|
1399
1427
|
action: z9.literal("start"),
|
|
@@ -1504,6 +1532,14 @@ var HeartbeatRequest = z9.object({
|
|
|
1504
1532
|
runnerId: z9.string().min(1),
|
|
1505
1533
|
daemonVersion: z9.string().min(1),
|
|
1506
1534
|
capabilities: CapabilityMatrix,
|
|
1535
|
+
/**
|
|
1536
|
+
* Kinds this device is withholding, and why it can be said.
|
|
1537
|
+
*
|
|
1538
|
+
* Optional so a daemon that has nothing withheld sends nothing, and so an
|
|
1539
|
+
* older daemon against a newer hub is simply a device with no withheld
|
|
1540
|
+
* kinds rather than a parse failure.
|
|
1541
|
+
*/
|
|
1542
|
+
withheld: z9.array(WithheldKind).default([]),
|
|
1507
1543
|
/**
|
|
1508
1544
|
* Leases this daemon believes it holds; the server renews exactly these.
|
|
1509
1545
|
*
|
|
@@ -1976,6 +2012,7 @@ export {
|
|
|
1976
2012
|
TERMINAL_STATES,
|
|
1977
2013
|
WireError,
|
|
1978
2014
|
WireErrorCode,
|
|
2015
|
+
WithheldKind,
|
|
1979
2016
|
backendDescriptor,
|
|
1980
2017
|
canTransition,
|
|
1981
2018
|
canonicalRequest,
|
|
@@ -1986,6 +2023,7 @@ export {
|
|
|
1986
2023
|
fingerprint,
|
|
1987
2024
|
generateKeys,
|
|
1988
2025
|
isBackendId,
|
|
2026
|
+
isCloudTaggedModel,
|
|
1989
2027
|
isJobKind,
|
|
1990
2028
|
isLocalHost,
|
|
1991
2029
|
isTerminal,
|