@byollm/protocol 0.1.0-alpha.58 → 0.1.0-alpha.59

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.58`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.59`) — 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.58` is that release, whole.
86
+ > so `0.1.0-alpha.59` 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
package/dist/index.d.ts CHANGED
@@ -477,7 +477,7 @@ declare const ChatMessage: z.ZodObject<{
477
477
  assistant: "assistant";
478
478
  }>;
479
479
  content: z.ZodString;
480
- }, z.core.$strip>;
480
+ }, z.core.$strict>;
481
481
  type ChatMessage = z.infer<typeof ChatMessage>;
482
482
  /**
483
483
  * Payload for `llm.generate`.
@@ -504,7 +504,7 @@ declare const ChatPayload: z.ZodObject<{
504
504
  assistant: "assistant";
505
505
  }>;
506
506
  content: z.ZodString;
507
- }, z.core.$strip>>;
507
+ }, z.core.$strict>>;
508
508
  system: z.ZodOptional<z.ZodString>;
509
509
  }, z.core.$strict>;
510
510
  type ChatPayload = z.infer<typeof ChatPayload>;
@@ -531,7 +531,7 @@ declare const KindedPayload: z.ZodDiscriminatedUnion<[z.ZodObject<{
531
531
  prompt: z.ZodString;
532
532
  system: z.ZodOptional<z.ZodString>;
533
533
  }, z.core.$strict>;
534
- }, z.core.$strip>, z.ZodObject<{
534
+ }, z.core.$strict>, z.ZodObject<{
535
535
  kind: z.ZodLiteral<"llm.chat">;
536
536
  payload: z.ZodObject<{
537
537
  messages: z.ZodArray<z.ZodObject<{
@@ -541,10 +541,10 @@ declare const KindedPayload: z.ZodDiscriminatedUnion<[z.ZodObject<{
541
541
  assistant: "assistant";
542
542
  }>;
543
543
  content: z.ZodString;
544
- }, z.core.$strip>>;
544
+ }, z.core.$strict>>;
545
545
  system: z.ZodOptional<z.ZodString>;
546
546
  }, z.core.$strict>;
547
- }, z.core.$strip>], "kind">;
547
+ }, z.core.$strict>], "kind">;
548
548
  type KindedPayload = z.infer<typeof KindedPayload>;
549
549
  /** The payload type for a given kind. */
550
550
  type PayloadFor<K extends JobKind> = K extends "llm.generate" ? GeneratePayload : ChatPayload;
@@ -591,7 +591,7 @@ declare const Lease: z.ZodObject<{
591
591
  id: z.ZodString;
592
592
  runnerId: z.ZodString;
593
593
  expiresAt: z.ZodNumber;
594
- }, z.core.$strip>;
594
+ }, z.core.$strict>;
595
595
  type Lease = z.infer<typeof Lease>;
596
596
  /** Payload union as it appears on a job record. */
597
597
  declare const JobPayload: z.ZodUnion<readonly [z.ZodObject<{
@@ -605,7 +605,7 @@ declare const JobPayload: z.ZodUnion<readonly [z.ZodObject<{
605
605
  assistant: "assistant";
606
606
  }>;
607
607
  content: z.ZodString;
608
- }, z.core.$strip>>;
608
+ }, z.core.$strict>>;
609
609
  system: z.ZodOptional<z.ZodString>;
610
610
  }, z.core.$strict>]>;
611
611
  type JobPayload = z.infer<typeof JobPayload>;
@@ -634,7 +634,7 @@ declare const ClaimedJob: z.ZodObject<{
634
634
  assistant: "assistant";
635
635
  }>;
636
636
  content: z.ZodString;
637
- }, z.core.$strip>>;
637
+ }, z.core.$strict>>;
638
638
  system: z.ZodOptional<z.ZodString>;
639
639
  }, z.core.$strict>]>;
640
640
  audience: z.ZodEnum<{
@@ -648,7 +648,7 @@ declare const ClaimedJob: z.ZodObject<{
648
648
  id: z.ZodString;
649
649
  runnerId: z.ZodString;
650
650
  expiresAt: z.ZodNumber;
651
- }, z.core.$strip>;
651
+ }, z.core.$strict>;
652
652
  }, z.core.$strict>;
653
653
  type ClaimedJob = z.infer<typeof ClaimedJob>;
654
654
  /**
@@ -979,11 +979,11 @@ declare const ClaimedStub: z.ZodObject<{
979
979
  id: z.ZodString;
980
980
  runnerId: z.ZodString;
981
981
  expiresAt: z.ZodNumber;
982
- }, z.core.$strip>;
982
+ }, z.core.$strict>;
983
983
  grant: z.ZodOptional<z.ZodObject<{
984
984
  grantId: z.ZodString;
985
985
  jobId: z.ZodString;
986
- siteId: z.ZodString;
986
+ site: z.ZodString;
987
987
  user: z.ZodString;
988
988
  owner: z.ZodString;
989
989
  purpose: z.ZodString;
@@ -1378,13 +1378,6 @@ declare const Purpose: z.ZodObject<{
1378
1378
  }>>;
1379
1379
  }, z.core.$strict>;
1380
1380
  type Purpose = z.infer<typeof Purpose>;
1381
- /**
1382
- * Everything a site needs, by purpose key.
1383
- *
1384
- * At least one purpose: a site that declares none is a site that can enqueue
1385
- * nothing, and accepting it would mean the first refusal a person saw came
1386
- * from a job rather than from registration.
1387
- */
1388
1381
  declare const Manifest: z.ZodRecord<z.ZodString, z.ZodObject<{
1389
1382
  label: z.ZodString;
1390
1383
  description: z.ZodOptional<z.ZodString>;
@@ -1509,7 +1502,7 @@ declare const GRANT_CONTEXT = "byollm/v1/grant";
1509
1502
  declare const SignedGrant: z.ZodObject<{
1510
1503
  grantId: z.ZodString;
1511
1504
  jobId: z.ZodString;
1512
- siteId: z.ZodString;
1505
+ site: z.ZodString;
1513
1506
  user: z.ZodString;
1514
1507
  owner: z.ZodString;
1515
1508
  purpose: z.ZodString;
@@ -1575,10 +1568,14 @@ type GrantRefusal =
1575
1568
  /** Older than {@link GRANT_MAX_AGE_MS}. */
1576
1569
  | "expired"
1577
1570
  /**
1578
- * Issued in the future.
1571
+ * Issued further in the future than clock drift explains.
1579
1572
  *
1580
1573
  * Checked, and not as pedantry: an `issuedAt` ahead of now extends a
1581
1574
  * grant's life past the bound, which is the whole thing being enforced.
1575
+ *
1576
+ * Tolerant by {@link CLOCK_SKEW_WARN_MS}, because it was tolerant by
1577
+ * nothing and that made ordinary drift a total outage — see
1578
+ * {@link verifyGrant}.
1582
1579
  */
1583
1580
  | "from-the-future";
1584
1581
  /**
@@ -2061,6 +2058,22 @@ declare const WithheldKind: z.ZodObject<{
2061
2058
  }, z.core.$strict>>;
2062
2059
  }, z.core.$strict>;
2063
2060
  type WithheldKind = z.infer<typeof WithheldKind>;
2061
+ /**
2062
+ * One grant, named by both halves — V1-3.
2063
+ *
2064
+ * A job id is chosen per site, so the lease id is the unique thing an upstream
2065
+ * and a daemon can both point at. Anywhere a request says "this piece of work,
2066
+ * held by me", it says it with both.
2067
+ *
2068
+ * Declared once because it was written out twice — `activeLeases` and
2069
+ * `ReleaseRequest.leases` — and both needed the same `.strict()` added. Two
2070
+ * copies of a shape are two places to forget it.
2071
+ */
2072
+ declare const GrantRef: z.ZodObject<{
2073
+ jobId: z.ZodString;
2074
+ leaseId: z.ZodString;
2075
+ }, z.core.$strict>;
2076
+ type GrantRef = z.infer<typeof GrantRef>;
2064
2077
  /**
2065
2078
  * Pairing is a device-code exchange, not a pasted secret
2066
2079
  * ({@link MUSTS.PAIR_INTERACTIVE}). The daemon starts a pairing, shows the
@@ -2079,7 +2092,7 @@ declare const PairStartRequest: z.ZodObject<{
2079
2092
  linux: "linux";
2080
2093
  win32: "win32";
2081
2094
  }>;
2082
- }, z.core.$strip>;
2095
+ }, z.core.$strict>;
2083
2096
  device: z.ZodObject<{
2084
2097
  identity: z.ZodString;
2085
2098
  encryption: z.ZodString;
@@ -2168,7 +2181,7 @@ declare const PairRequest: z.ZodDiscriminatedUnion<[z.ZodObject<{
2168
2181
  linux: "linux";
2169
2182
  win32: "win32";
2170
2183
  }>;
2171
- }, z.core.$strip>;
2184
+ }, z.core.$strict>;
2172
2185
  device: z.ZodObject<{
2173
2186
  identity: z.ZodString;
2174
2187
  encryption: z.ZodString;
@@ -2286,11 +2299,11 @@ declare const ClaimResponse: z.ZodObject<{
2286
2299
  id: z.ZodString;
2287
2300
  runnerId: z.ZodString;
2288
2301
  expiresAt: z.ZodNumber;
2289
- }, z.core.$strip>;
2302
+ }, z.core.$strict>;
2290
2303
  grant: z.ZodOptional<z.ZodObject<{
2291
2304
  grantId: z.ZodString;
2292
2305
  jobId: z.ZodString;
2293
- siteId: z.ZodString;
2306
+ site: z.ZodString;
2294
2307
  user: z.ZodString;
2295
2308
  owner: z.ZodString;
2296
2309
  purpose: z.ZodString;
@@ -2360,7 +2373,7 @@ declare const HeartbeatRequest: z.ZodObject<{
2360
2373
  activeLeases: z.ZodArray<z.ZodObject<{
2361
2374
  jobId: z.ZodString;
2362
2375
  leaseId: z.ZodString;
2363
- }, z.core.$strip>>;
2376
+ }, z.core.$strict>>;
2364
2377
  paused: z.ZodBoolean;
2365
2378
  }, z.core.$strict>;
2366
2379
  type HeartbeatRequest = z.infer<typeof HeartbeatRequest>;
@@ -2445,7 +2458,7 @@ declare const ReleaseRequest: z.ZodObject<{
2445
2458
  leases: z.ZodArray<z.ZodObject<{
2446
2459
  jobId: z.ZodString;
2447
2460
  leaseId: z.ZodString;
2448
- }, z.core.$strip>>;
2461
+ }, z.core.$strict>>;
2449
2462
  reason: z.ZodEnum<{
2450
2463
  refused: "refused";
2451
2464
  shutdown: "shutdown";
@@ -2526,4 +2539,4 @@ declare const FetchResponse: z.ZodObject<{
2526
2539
  }, z.core.$strict>;
2527
2540
  type FetchResponse = z.infer<typeof FetchResponse>;
2528
2541
 
2529
- export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, CLOCK_ATTRIBUTION_MS, CLOCK_SKEW_WARN_MS, 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, GRANT_CONTEXT, GRANT_MAX_AGE_MS, GRANT_SIGNED_FIELDS, GeneratePayload, type GrantClaims, type GrantRefusal, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobRefused, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, Manifest, 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, Purpose, REFUSAL_MESSAGES, RESERVED_PURPOSE, RETIREMENT_WINDOW_MS, RefusalReason, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SignedGrant, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, backendName, canTransition, canonicalRequest, checkProtocolVersion, classifyCost, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, grantStatement, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signGrant, signRequest, signSiteRequest, signSuccession, signWith, singlePurposeManifest, sizeClassCeiling, sizeClassOf, successionStatement, verifyGrant, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
2542
+ export { AUDIENCES, Audience, BACKENDS, BACKEND_IDS, BackendClass, BackendCost, type BackendDescriptor, type BackendId, BackendIdSchema, CLOCK_ATTRIBUTION_MS, CLOCK_SKEW_WARN_MS, 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, GRANT_CONTEXT, GRANT_MAX_AGE_MS, GRANT_SIGNED_FIELDS, GeneratePayload, type GrantClaims, GrantRef, type GrantRefusal, HeartbeatRequest, HeartbeatResponse, JOB_KINDS, JobKind, JobOutcome, JobPayload, JobRefused, JobResultCanceled, JobResultError, JobResultOk, JobState, JobStub, KindedPayload, Lease, MAX_CLOCK_SKEW_MS, MAX_SUCCESSION_CHAIN, MIN_PROTOCOL_VERSION, MUSTS, MUST_IDS, Manifest, 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, Purpose, REFUSAL_MESSAGES, RESERVED_PURPOSE, RETIREMENT_WINDOW_MS, RefusalReason, ReleaseRequest, ReleaseResponse, RequestSignature, ResultDisposition, ResultProvenance, ResultRequest, ResultResponse, RunMetadata, SIZE_CLASS_LIMITS, SUCCESSION_CONTEXT, SUPPORTED_PROTOCOL_VERSIONS, SealedEnvelope, SealedOutcome, type SignatureFailure, SignedGrant, SizeClass, type SpendConsent, StoredKeys, Succession, type SuccessionFailure, type SuccessionWalk, TERMINAL_STATES, type VersionRefusal, WireError, WireErrorCode, WithheldKind, backendDescriptor, backendName, canTransition, canonicalRequest, checkProtocolVersion, classifyCost, cryptoReady, declaredVersion, effectiveOfferScope, fingerprint, generateKeys, grantStatement, isBackendId, isCloudTaggedModel, isJobKind, isLocalHost, isTerminal, keyId, kindsOf, matchAudience, mustsVerifiedBy, open, payloadTextLength, provenanceFor, publicIdentityOf, resolveCost, seal, signGrant, signRequest, signSiteRequest, signSuccession, signWith, singlePurposeManifest, sizeClassCeiling, sizeClassOf, successionStatement, verifyGrant, verifyLink, verifyPublicIdentity, verifyRequest, verifySiteRequest, verifyWith, walkSuccession };
package/dist/index.js CHANGED
@@ -348,7 +348,7 @@ var PAYLOAD_LIMITS = Object.freeze({
348
348
  var ChatMessage = z3.object({
349
349
  role: z3.enum(["system", "user", "assistant"]),
350
350
  content: z3.string().max(PAYLOAD_LIMITS.maxTextChars)
351
- });
351
+ }).strict();
352
352
  var GeneratePayload = z3.object({
353
353
  prompt: z3.string().min(1).max(PAYLOAD_LIMITS.maxTextChars),
354
354
  system: z3.string().max(PAYLOAD_LIMITS.maxTextChars).optional()
@@ -370,8 +370,11 @@ var ChatPayload = z3.object({
370
370
  var JobKind = z3.enum(["llm.generate", "llm.chat"]);
371
371
  var JOB_KINDS = Object.freeze(JobKind.options);
372
372
  var KindedPayload = z3.discriminatedUnion("kind", [
373
- z3.object({ kind: z3.literal("llm.generate"), payload: GeneratePayload }),
374
- z3.object({ kind: z3.literal("llm.chat"), payload: ChatPayload })
373
+ // Strict on the wrappers too. A union member that strips is a door beside
374
+ // the one that is locked: the payloads inside are strict, and an extra key
375
+ // on the envelope vanished just as quietly.
376
+ z3.object({ kind: z3.literal("llm.generate"), payload: GeneratePayload }).strict(),
377
+ z3.object({ kind: z3.literal("llm.chat"), payload: ChatPayload }).strict()
375
378
  ]);
376
379
  function isJobKind(value) {
377
380
  return JOB_KINDS.includes(value);
@@ -542,8 +545,29 @@ var SignedGrant = z5.object({
542
545
  * attack, and this field is why it fails.
543
546
  */
544
547
  jobId: z5.string().min(1),
545
- /** The site the work came from. */
546
- siteId: z5.string().min(1),
548
+ /**
549
+ * The site the work came from, **as a key id** — byollm-review 2026-08-27.
550
+ *
551
+ * This was `siteId`, holding the site's id in the control plane's
552
+ * namespace, and it was signed by the engine and read by nobody. A signed
553
+ * field nobody checks is not a weak guarantee, it is the appearance of
554
+ * one: the design says "the grant carries the site", and nothing anywhere
555
+ * compared it to anything.
556
+ *
557
+ * It could not be compared. Job ids are chosen per site, so a grant
558
+ * authored for (site A, `job_1`) satisfied every device check against a
559
+ * stub naming (site B, `job_1`) — but the device holds sites only by the
560
+ * key ids it pinned, and had no way to relate a control-plane uuid to
561
+ * one. Checking the field would have meant a lookup through the party the
562
+ * grant exists to distrust.
563
+ *
564
+ * So the namespace changes to the one the device already has, and the
565
+ * name changes with it: this is the same value as {@link JobStub.site},
566
+ * compared directly, no lookup and nothing to believe. The control-plane
567
+ * id is not carried alongside — it had no reader, and keeping an
568
+ * unchecked field beside a checked one is how this hole was dug.
569
+ */
570
+ site: z5.string().min(1),
547
571
  /** Whose job it is — the person the site enqueued for. */
548
572
  user: z5.string().min(1),
549
573
  /**
@@ -593,7 +617,7 @@ function verifyGrant(input) {
593
617
  if (grant.owner !== input.owner) return "wrong-owner";
594
618
  if (grant.jobId !== input.jobId) return "wrong-job";
595
619
  const age = now - grant.issuedAt;
596
- if (age < 0) return "from-the-future";
620
+ if (age < -CLOCK_SKEW_WARN_MS) return "from-the-future";
597
621
  if (age > (input.maxAgeMs ?? GRANT_MAX_AGE_MS)) return "expired";
598
622
  return verifyWith(
599
623
  input.controlPlanePublic,
@@ -655,7 +679,7 @@ var Lease = z6.object({
655
679
  runnerId: z6.string().min(1),
656
680
  /** Epoch milliseconds after which the claim is void. */
657
681
  expiresAt: z6.number().int().positive()
658
- });
682
+ }).strict();
659
683
  var JobPayload = z6.union([GeneratePayload, ChatPayload]);
660
684
  var ClaimedJob = z6.object({
661
685
  id: z6.string().min(1),
@@ -1113,6 +1137,13 @@ function verifyRequest(input) {
1113
1137
  // src/manifest.ts
1114
1138
  import { z as z9 } from "zod";
1115
1139
  var RESERVED_PURPOSE = "default";
1140
+ var RENDERABLE = /^[^\p{Cc}\p{Cf}\p{Cs}\p{Co}]+$/u;
1141
+ var renderable = (max, what) => z9.string().min(1).max(max).regex(
1142
+ RENDERABLE,
1143
+ `a ${what} is text a person reads \u2014 no control characters, direction overrides or zero-width padding`
1144
+ ).refine((value) => value.trim() !== "", {
1145
+ message: `a ${what} cannot be blank`
1146
+ });
1116
1147
  var PurposeKey = z9.string().regex(
1117
1148
  /^[a-z0-9][a-z0-9-]*$/,
1118
1149
  "a purpose key is a lowercase slug \u2014 letters, digits and hyphens"
@@ -1125,9 +1156,9 @@ var Purpose = z9.object({
1125
1156
  * compromise between machines and this is not. "Writing Assistant" is
1126
1157
  * what somebody understands; `writing-assistant` is what travels.
1127
1158
  */
1128
- label: z9.string().min(1).max(80),
1159
+ label: renderable(80, "label"),
1129
1160
  /** One line of context for the consent screen. Optional. */
1130
- description: z9.string().min(1).max(280).optional(),
1161
+ description: renderable(280, "description").optional(),
1131
1162
  /**
1132
1163
  * The kinds this purpose uses.
1133
1164
  *
@@ -1135,10 +1166,15 @@ var Purpose = z9.object({
1135
1166
  * person can send this purpose's chat to one service and its generation
1136
1167
  * to another. Listing a kind here is what makes that slot appear.
1137
1168
  */
1138
- kinds: z9.array(JobKind).min(1)
1169
+ kinds: z9.array(JobKind).min(1).max(JOB_KINDS.length).refine((kinds) => new Set(kinds).size === kinds.length, {
1170
+ message: "a purpose lists each kind once"
1171
+ })
1139
1172
  }).strict();
1173
+ var MAX_PURPOSES = 32;
1140
1174
  var Manifest = z9.record(PurposeKey, Purpose).refine((manifest) => Object.keys(manifest).length > 0, {
1141
1175
  message: "a manifest declares at least one purpose"
1176
+ }).refine((manifest) => Object.keys(manifest).length <= MAX_PURPOSES, {
1177
+ message: `a manifest declares at most ${String(MAX_PURPOSES)} purposes \u2014 a consent screen is a set of questions somebody answers one at a time`
1142
1178
  }).refine((manifest) => !(RESERVED_PURPOSE in manifest), {
1143
1179
  message: `"${RESERVED_PURPOSE}" is reserved for a site that declares no purposes of its own \u2014 give this one a name from your own vocabulary`
1144
1180
  });
@@ -1716,6 +1752,7 @@ var WithheldKind = z11.object({
1716
1752
  z11.object({ service: z11.string().min(1), offer: OfferScope }).strict()
1717
1753
  ).min(2)
1718
1754
  }).strict();
1755
+ var GrantRef = z11.object({ jobId: z11.string().min(1), leaseId: z11.string().min(1) }).strict();
1719
1756
  var PairStartRequest = z11.object({
1720
1757
  protocolVersion: z11.literal(PROTOCOL_VERSION),
1721
1758
  action: z11.literal("start"),
@@ -1724,7 +1761,7 @@ var PairStartRequest = z11.object({
1724
1761
  /** Shown in the app's runner list so a user can tell their machines apart. */
1725
1762
  label: z11.string().min(1).max(120),
1726
1763
  platform: z11.enum(["darwin", "linux", "win32"])
1727
- }),
1764
+ }).strict(),
1728
1765
  /**
1729
1766
  * This machine's public keys (byollm_009 §5).
1730
1767
  *
@@ -1861,9 +1898,7 @@ var HeartbeatRequest = z11.object({
1861
1898
  * Lease ids rather than job ids, so a replayed heartbeat cannot renew a
1862
1899
  * grant the runner no longer holds — see {@link Lease.id}.
1863
1900
  */
1864
- activeLeases: z11.array(
1865
- z11.object({ jobId: z11.string().min(1), leaseId: z11.string().min(1) })
1866
- ),
1901
+ activeLeases: z11.array(GrantRef),
1867
1902
  /** True while the owner has the daemon paused; the server stops offering work. */
1868
1903
  paused: z11.boolean()
1869
1904
  }).strict();
@@ -2073,9 +2108,7 @@ var ReleaseRequest = z11.object({
2073
2108
  * moment it arrives, which for a replayed request is not the lease the
2074
2109
  * daemon meant. See {@link Lease.id}.
2075
2110
  */
2076
- leases: z11.array(
2077
- z11.object({ jobId: z11.string().min(1), leaseId: z11.string().min(1) })
2078
- ),
2111
+ leases: z11.array(GrantRef),
2079
2112
  /**
2080
2113
  * Why, so the app's runner list can say something true.
2081
2114
  *
@@ -2281,6 +2314,7 @@ export {
2281
2314
  GRANT_MAX_AGE_MS,
2282
2315
  GRANT_SIGNED_FIELDS,
2283
2316
  GeneratePayload,
2317
+ GrantRef,
2284
2318
  HeartbeatRequest,
2285
2319
  HeartbeatResponse,
2286
2320
  JOB_KINDS,