byollm 0.1.0-alpha.21 → 0.1.0-alpha.23
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 +13 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-ZGQPZK66.js → chunk-7EO6XN4N.js} +75 -9
- package/dist/chunk-7EO6XN4N.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-ZGQPZK66.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
> [!WARNING]
|
|
2
|
-
> **Alpha (`0.1.0-alpha.
|
|
2
|
+
> **Alpha (`0.1.0-alpha.23`) — under active development. Don't use this yet.**
|
|
3
3
|
>
|
|
4
4
|
> Install it deliberately: `npx byollm@alpha`, or `npm install byollm@alpha`.
|
|
5
5
|
>
|
|
@@ -79,6 +79,18 @@
|
|
|
79
79
|
> `byollm offer <backend> public --cap <cents>`. Local base URLs are
|
|
80
80
|
> unaffected. `byollm backends` shows the cost class per route.
|
|
81
81
|
|
|
82
|
+
<!-- release-note 0.1.0-alpha.21 -->
|
|
83
|
+
> [!NOTE]
|
|
84
|
+
> **`0.1.0-alpha.20` is not a complete release — do not pin it.** Four
|
|
85
|
+
> packages published and `@byollm/server` did not: a Sigstore
|
|
86
|
+
> transparency-log 409 on its provenance attestation. The workflow's
|
|
87
|
+
> "already published" guard correctly refuses to resume a partial publish,
|
|
88
|
+
> so `0.1.0-alpha.23` is that release, whole.
|
|
89
|
+
>
|
|
90
|
+
> If you run the Supabase adapter, `alpha.21` needs
|
|
91
|
+
> `20260819010000_completed_by_lease_id.sql`: alpha.19 shipped §3.6's
|
|
92
|
+
> ordering without the column it stores the grant in.
|
|
93
|
+
|
|
82
94
|
# `byollm`
|
|
83
95
|
|
|
84
96
|
What end users run. Connects **outbound** to an app you trust, claims only the
|
package/dist/bin.js
CHANGED
|
@@ -1892,6 +1892,7 @@ var Runner = class {
|
|
|
1892
1892
|
#capabilities = [];
|
|
1893
1893
|
#paused = false;
|
|
1894
1894
|
#revoked = false;
|
|
1895
|
+
#awaitingConsent = false;
|
|
1895
1896
|
#stopped = false;
|
|
1896
1897
|
#lastError;
|
|
1897
1898
|
#completed = 0;
|
|
@@ -2174,6 +2175,15 @@ var Runner = class {
|
|
|
2174
2175
|
type: "heartbeat",
|
|
2175
2176
|
capabilities: capabilities.length
|
|
2176
2177
|
});
|
|
2178
|
+
if (heartbeat.awaitingConsent === true) {
|
|
2179
|
+
if (!this.#awaitingConsent) {
|
|
2180
|
+
this.#awaitingConsent = true;
|
|
2181
|
+
this.#options.onEvent?.({ type: "awaiting-consent" });
|
|
2182
|
+
}
|
|
2183
|
+
} else if (this.#awaitingConsent) {
|
|
2184
|
+
this.#awaitingConsent = false;
|
|
2185
|
+
this.#options.onEvent?.({ type: "consent-resumed" });
|
|
2186
|
+
}
|
|
2177
2187
|
if (heartbeat.revoked) {
|
|
2178
2188
|
this.#revoked = true;
|
|
2179
2189
|
this.cancelAll();
|
|
@@ -2276,12 +2286,21 @@ var Runner = class {
|
|
|
2276
2286
|
// everything about it.
|
|
2277
2287
|
plaintext: JSON.stringify({ outcome, ran }),
|
|
2278
2288
|
senderKeys: keys,
|
|
2279
|
-
|
|
2289
|
+
// Back to the site that sent it, which is not necessarily the only
|
|
2290
|
+
// site this machine serves. Sealing to `sitePinned` would send site B's
|
|
2291
|
+
// answer to site A — unopenable there, and readable by nobody, which
|
|
2292
|
+
// presents as a job that ran and never came back.
|
|
2293
|
+
recipientEncryptionPublic: this.#pinFor(job).encryption,
|
|
2280
2294
|
context: {
|
|
2281
2295
|
jobId: job.id,
|
|
2282
2296
|
senderKeyId: keyId(publicIdentityOf2(keys).identity),
|
|
2283
|
-
recipientKeyId: keyId(
|
|
2284
|
-
|
|
2297
|
+
recipientKeyId: keyId(this.#pinFor(job).identity),
|
|
2298
|
+
// This runner's clock, not the process's — cloud_008 §31. The only
|
|
2299
|
+
// `Date.now()` left in this class, in the one place that stamps a
|
|
2300
|
+
// deadline somebody else enforces: a test that moves time moved every
|
|
2301
|
+
// other clock here and not this one, so a sealed result carried an
|
|
2302
|
+
// expiry from a different timeline than the lease it answered.
|
|
2303
|
+
deadlineAt: this.#now() + ENVELOPE_MAX_AGE_MS,
|
|
2285
2304
|
direction: "result"
|
|
2286
2305
|
}
|
|
2287
2306
|
});
|
|
@@ -2345,16 +2364,17 @@ var Runner = class {
|
|
|
2345
2364
|
);
|
|
2346
2365
|
}
|
|
2347
2366
|
const keys = await identity.keys();
|
|
2348
|
-
const
|
|
2349
|
-
|
|
2367
|
+
const pinned = this.#pinFor(job);
|
|
2368
|
+
const pinnedKeyId = keyId(pinned.identity);
|
|
2369
|
+
if (envelope.senderKeyId !== job.site) {
|
|
2350
2370
|
throw new Error(
|
|
2351
|
-
`refusing job ${job.id}:
|
|
2371
|
+
`refusing job ${job.id}: the stub names site ${job.site}, but the payload declares it was sealed by ${envelope.senderKeyId}`
|
|
2352
2372
|
);
|
|
2353
2373
|
}
|
|
2354
2374
|
const opened = await open({
|
|
2355
2375
|
envelope,
|
|
2356
2376
|
recipientKeys: keys,
|
|
2357
|
-
senderIdentityPublic:
|
|
2377
|
+
senderIdentityPublic: pinned.identity,
|
|
2358
2378
|
expected: {
|
|
2359
2379
|
jobId: job.id,
|
|
2360
2380
|
senderKeyId: pinnedKeyId,
|
|
@@ -2369,6 +2389,39 @@ var Runner = class {
|
|
|
2369
2389
|
}
|
|
2370
2390
|
return JSON.parse(opened.plaintext);
|
|
2371
2391
|
}
|
|
2392
|
+
/**
|
|
2393
|
+
* The pinned key for the site a stub names — cloud_009 §5.
|
|
2394
|
+
*
|
|
2395
|
+
* One place, because both legs need it and they must agree: opening the
|
|
2396
|
+
* payload with site A's key while sealing the answer to site B is a job
|
|
2397
|
+
* that runs, produces something nobody can read, and reports success.
|
|
2398
|
+
*
|
|
2399
|
+
* A site the map does not hold is refused by name rather than falling back
|
|
2400
|
+
* to any key at hand. The fallback is the failure this exists to prevent —
|
|
2401
|
+
* the relay chooses `stub.site`, and a daemon that treats an unknown site
|
|
2402
|
+
* as "probably the one I know" has handed the choice of which key verifies
|
|
2403
|
+
* its work to the party the pinning is defending against.
|
|
2404
|
+
*/
|
|
2405
|
+
#pinFor(job) {
|
|
2406
|
+
const identity = this.#options.identity;
|
|
2407
|
+
if (!identity) {
|
|
2408
|
+
throw new Error("this daemon has no keys, so it has no site to pin");
|
|
2409
|
+
}
|
|
2410
|
+
const fromMap = identity.sites?.get(job.site);
|
|
2411
|
+
if (fromMap) return fromMap;
|
|
2412
|
+
if (job.site === keyId(identity.sitePinned.identity)) {
|
|
2413
|
+
return identity.sitePinned;
|
|
2414
|
+
}
|
|
2415
|
+
const paired = [
|
|
2416
|
+
.../* @__PURE__ */ new Set([
|
|
2417
|
+
keyId(identity.sitePinned.identity),
|
|
2418
|
+
...identity.sites?.keys() ?? []
|
|
2419
|
+
])
|
|
2420
|
+
].sort();
|
|
2421
|
+
throw new Error(
|
|
2422
|
+
`refusing job ${job.id}: it names site ${job.site}, which this machine is not paired with (paired with ${paired.join(", ")})`
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2372
2425
|
/**
|
|
2373
2426
|
* Report-and-forget.
|
|
2374
2427
|
*
|
|
@@ -2695,6 +2748,19 @@ function report(origin, event, io) {
|
|
|
2695
2748
|
break;
|
|
2696
2749
|
case "revoked":
|
|
2697
2750
|
io.out(`${at} ${host} this runner was revoked. Stopping.
|
|
2751
|
+
`);
|
|
2752
|
+
break;
|
|
2753
|
+
// Not a fault and not a revocation: the terms this machine runs under
|
|
2754
|
+
// changed, and the person who has to read them is the one at this
|
|
2755
|
+
// keyboard. The daemon keeps running and keeps its pairing.
|
|
2756
|
+
case "awaiting-consent":
|
|
2757
|
+
io.out(
|
|
2758
|
+
`${at} ${host} paused \u2014 the terms changed and are waiting for you. Open your connections page to read them; nothing runs until you do.
|
|
2759
|
+
`
|
|
2760
|
+
);
|
|
2761
|
+
break;
|
|
2762
|
+
case "consent-resumed":
|
|
2763
|
+
io.out(`${at} ${host} resumed \u2014 thank you.
|
|
2698
2764
|
`);
|
|
2699
2765
|
break;
|
|
2700
2766
|
case "error":
|
|
@@ -3158,7 +3224,7 @@ async function main(argv) {
|
|
|
3158
3224
|
}
|
|
3159
3225
|
|
|
3160
3226
|
// src/index.ts
|
|
3161
|
-
var DAEMON_VERSION = "0.1.0-alpha.
|
|
3227
|
+
var DAEMON_VERSION = "0.1.0-alpha.23";
|
|
3162
3228
|
function daemonVersion() {
|
|
3163
3229
|
return {
|
|
3164
3230
|
daemon: DAEMON_VERSION,
|
|
@@ -3210,4 +3276,4 @@ export {
|
|
|
3210
3276
|
runCli,
|
|
3211
3277
|
main
|
|
3212
3278
|
};
|
|
3213
|
-
//# sourceMappingURL=chunk-
|
|
3279
|
+
//# sourceMappingURL=chunk-7EO6XN4N.js.map
|