@everfur/cli 0.7.0 → 0.9.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.
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ /*! @everfur/cli. Copyright (c) 2026 Strand Health Inc. dba Everfur. All rights reserved. Use is subject to the Everfur SDK License: https://docs.everfur.com/license */
2
3
  import { mkdirSync, writeFileSync, renameSync, readFileSync, readdirSync, statSync } from 'fs';
3
4
  import { join, isAbsolute, resolve, dirname, relative, sep } from 'path';
5
+ import { createHash, createHmac } from 'crypto';
4
6
  import { parse } from 'yaml';
5
7
  import Ajv2020 from 'ajv/dist/2020.js';
6
8
  import addFormats from 'ajv-formats';
7
- import { createHash } from 'crypto';
8
9
  import { z } from 'zod';
9
10
 
10
11
  var NO_CONTRACT_CACHE = Object.freeze({
@@ -113,13 +114,13 @@ var fetchTransport = Object.freeze({
113
114
  if (name === "TimeoutError" || name === "AbortError") {
114
115
  throw new TransportError("timeout", `no response within ${request.timeoutMs}ms`);
115
116
  }
116
- throw new TransportError("network", cause instanceof Error ? cause.message : String(cause));
117
+ throw new TransportError("network", describeNetworkFailure(cause));
117
118
  }
118
119
  let body;
119
120
  try {
120
121
  body = await response.text();
121
122
  } catch (cause) {
122
- throw new TransportError("network", cause instanceof Error ? cause.message : String(cause));
123
+ throw new TransportError("network", describeNetworkFailure(cause));
123
124
  }
124
125
  const headers = {};
125
126
  response.headers.forEach((value, key) => {
@@ -128,6 +129,15 @@ var fetchTransport = Object.freeze({
128
129
  return Object.freeze({ status: response.status, headers: Object.freeze(headers), body });
129
130
  }
130
131
  });
132
+ function describeNetworkFailure(cause) {
133
+ if (!(cause instanceof Error)) return String(cause);
134
+ const inner = cause.cause;
135
+ if (inner instanceof Error && inner.message.length > 0 && inner.message !== cause.message) {
136
+ return `${cause.message} (${inner.message})`;
137
+ }
138
+ const code = typeof inner === "object" && inner !== null ? inner.code : void 0;
139
+ return typeof code === "string" && code.length > 0 ? `${cause.message} (${code})` : cause.message;
140
+ }
131
141
 
132
142
  // src/time/clock.ts
133
143
  var systemClock = Object.freeze({
@@ -231,19 +241,20 @@ function resolveEndpoint(flagValue, env) {
231
241
  ]
232
242
  };
233
243
  }
244
+ const named = source === "flag" ? "--base-url" : BASE_URL_ENV_VAR;
234
245
  let parsed;
235
246
  try {
236
247
  parsed = new URL(raw);
237
248
  } catch {
238
- return { ok: false, errors: [`--base-url is not a URL: ${raw}`] };
249
+ return { ok: false, errors: [`${named} is not a URL: ${raw}`] };
239
250
  }
240
251
  if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
241
- return { ok: false, errors: [`--base-url must be http or https, not ${parsed.protocol}`] };
252
+ return { ok: false, errors: [`${named} must be http or https, not ${parsed.protocol}`] };
242
253
  }
243
254
  if (parsed.protocol === "http:" && !LOCAL_HTTP_HOSTS.has(parsed.hostname)) {
244
255
  return {
245
256
  ok: false,
246
- errors: [`--base-url must be https (http only on localhost, 127.0.0.1 or [::1]), not http://${parsed.host}`]
257
+ errors: [`${named} must be https (http only on localhost, 127.0.0.1 or [::1]), not http://${parsed.host}`]
247
258
  };
248
259
  }
249
260
  const normalised = stripTrailingSlashes(`${parsed.origin}${parsed.pathname}`);
@@ -260,8 +271,15 @@ function apiUrl(endpoint, path) {
260
271
  const suffix = path.startsWith("/") ? path : `/${path}`;
261
272
  return endpoint.prefixIncluded ? `${endpoint.baseUrl}${suffix}` : `${endpoint.baseUrl}${API_PREFIX}${suffix}`;
262
273
  }
263
-
264
- // src/config/credentials.ts
274
+ var SECRET_KEY_API_HOSTS = /* @__PURE__ */ new Set(["api.everfur.com", "api-staging.everfur.com"]);
275
+ var ALLOW_CUSTOM_API_HOST_ENV_VAR = "EVERFUR_ALLOW_CUSTOM_API_HOST";
276
+ function secretKeyHostProblem(endpoint, env) {
277
+ if ((env[ALLOW_CUSTOM_API_HOST_ENV_VAR] ?? "").trim() === "1") return null;
278
+ const url = new URL(endpoint.baseUrl);
279
+ if (url.protocol === "https:" && SECRET_KEY_API_HOSTS.has(url.hostname)) return null;
280
+ if (LOCAL_HTTP_HOSTS.has(url.hostname)) return null;
281
+ return `${BASE_URL_ENV_VAR} names ${url.host}, which is not api.everfur.com, api-staging.everfur.com or this machine, so the secret key is not sent to it. Set ${ALLOW_CUSTOM_API_HOST_ENV_VAR}=1 in the shell only if that host is an Everfur API you trust`;
282
+ }
265
283
  var REDACTED = "[redacted]";
266
284
  var PARTNER_KEY = Object.freeze({
267
285
  envVar: "EVERFUR_PARTNER_KEY",
@@ -275,8 +293,12 @@ var PARTNER_KEY = Object.freeze({
275
293
  var PARTNER_SECRET_KEY = Object.freeze({
276
294
  envVar: "EVERFUR_PARTNER_SECRET_KEY",
277
295
  prefix: "sk_partner_",
296
+ // The session mint accepts both secret families on this one header (EFBackend sessions_router
297
+ // `_SECRET_KEY_FAMILIES`): the unrestricted sk_partner_ key and the rk_partner_ restricted key the plan
298
+ // already names. Both prefixes are 11 characters, so one expected length still covers either.
299
+ alsoAccepts: Object.freeze(["rk_partner_"]),
278
300
  length: "sk_partner_".length + 64,
279
- summary: "Partner secret key (sk_partner_...). Presented only to the session mint route."
301
+ summary: "Partner secret key (sk_partner_..., or an rk_partner_... restricted key). Presented only to the session mint route."
280
302
  });
281
303
  var DOCS_KEY = Object.freeze({
282
304
  envVar: "EVERFUR_DOCS_KEY",
@@ -296,6 +318,21 @@ var ADMIN_TOKEN = Object.freeze({
296
318
  length: null,
297
319
  summary: "Admin bearer token for the /admin routes. Required by `sandbox create`."
298
320
  });
321
+ var WEBHOOK_SIGNING_SECRET = Object.freeze({
322
+ envVar: "EVERFUR_WEBHOOK_SECRET",
323
+ prefix: "whsec_",
324
+ length: null,
325
+ summary: "A claims webhook endpoint signing secret (whsec_...). Read only to sign test deliveries to your own receiver."
326
+ });
327
+ var CLAIMS_INBOUND_SECRET = Object.freeze({
328
+ envVar: "EVERFUR_CLAIMS_INBOUND_SECRET",
329
+ prefix: "whsec_",
330
+ length: 70,
331
+ summary: "A claims inbound endpoint shared secret (whsec_...). Read only to sign sandbox sample events."
332
+ });
333
+ function publishableKeyShapes() {
334
+ return [...PARTNER_KEY.alsoAccepts ?? [], PARTNER_KEY.prefix].map((prefix) => `${prefix}...`).join(" or ");
335
+ }
299
336
  var CREDENTIAL_SPECS = Object.freeze([
300
337
  PARTNER_KEY,
301
338
  PARTNER_SECRET_KEY,
@@ -365,6 +402,12 @@ function resolveCredential(env, spec) {
365
402
  matchedPrefix: accepted.find((p) => raw.startsWith(p)) ?? null
366
403
  });
367
404
  }
405
+ function hmacSha256Hex(credential, message) {
406
+ return hmacSha256(credential, message).toString("hex");
407
+ }
408
+ function hmacSha256(credential, message) {
409
+ return createHmac("sha256", Buffer.from(credential.reveal(), "utf8")).update(message).digest();
410
+ }
368
411
 
369
412
  // src/detect/theme-color.ts
370
413
  var NAMED = Object.freeze({ white: "#FFFFFF", black: "#000000" });
@@ -4832,7 +4875,7 @@ function sdkInstallSpec() {
4832
4875
  return `${SDK_PACKAGE}@^${SDK_MIN_VERSION}` ;
4833
4876
  }
4834
4877
  var SDK_PACKAGE_PLATFORMS = /* @__PURE__ */ new Set(["expo-managed", "bare-react-native", "web"]);
4835
- var SDK_MIN_VERSION = "0.11.0";
4878
+ var SDK_MIN_VERSION = "0.17.0";
4836
4879
  var SDK_WEB_MIN_VERSION = SDK_MIN_VERSION;
4837
4880
  var SDK_TELEVET_MIN_VERSION = SDK_MIN_VERSION;
4838
4881
  function sdkInstallSpecFor(options) {
@@ -4914,7 +4957,7 @@ function televetCallInstallSpecs(options) {
4914
4957
  );
4915
4958
  }
4916
4959
  var TELEVET_WEB_CALL_MODULE = Object.freeze({ name: "@daily-co/daily-js", spec: "^0.91.0" });
4917
- var SDK_CONTRACT_VERSION = "2026-08-01";
4960
+ var SDK_CONTRACT_VERSION = "2026-09-19";
4918
4961
  function platformUnsupportedReason(projectType) {
4919
4962
  return `${SDK_PACKAGE} publishes no entry point for a "${projectType}" project: its device entry points import react-native, its web entry point renders with react-dom, and neither resolves inside this project shape. Until the contract names a package or install commands for the shape no plan can be produced for it, and substituting another entry point would produce a bundle that does not build.`;
4920
4963
  }
@@ -5433,8 +5476,8 @@ function booleanAttribute(outcome, key) {
5433
5476
  }
5434
5477
 
5435
5478
  // src/version.ts
5436
- var CLI_VERSION = "0.7.0";
5437
- var CLI_PUBLISHED_VERSION = "0.5.0";
5479
+ var CLI_VERSION = "0.9.0";
5480
+ var CLI_PUBLISHED_VERSION = "0.8.0";
5438
5481
 
5439
5482
  // src/commands/diagnose/reasons.ts
5440
5483
  var REASON_CODES = Object.freeze([
@@ -6394,6 +6437,16 @@ var THEME_SLOT_NAMES = Object.freeze([
6394
6437
  // tab the tabs and segmented controls
6395
6438
  // bookingStep the container of one booking step
6396
6439
  // dialog the dialogs and sheets
6440
+ // And since 15 Oct 2026 the Health Plan's cart bar (`cartBar`): the bar that carries the cart count, the subtotal
6441
+ // and the checkout control. Its default fill is the brand colour, so its text is guarded on that.
6442
+ // And the Health Plan's own two (15 Oct 2026), so a shop can differ from every other SDK card and chip:
6443
+ // planCard a Health Plan product card (fill, edge, radius, ink). Unset, it follows `card`.
6444
+ // planReasonLabel the label of a reason drawn as a row (`reasonVariant: 'rows'`): only its ink is read. Unset,
6445
+ // it follows the `chip` ink, then brand ink.
6446
+ // And the plan page's two link washes (22 Oct 2026), so a partner can give his exact tints rather than the mix:
6447
+ // planWash the soft link wash (the icon tiles, the tip, the "Add her weight" row): only its fill is read.
6448
+ // planChip the stronger link wash of a chip: only its fill is read.
6449
+ // Unset, each is the link ink mixed over the card (12% and 20%).
6397
6450
  "header",
6398
6451
  "banner",
6399
6452
  "chip",
@@ -6401,8 +6454,18 @@ var THEME_SLOT_NAMES = Object.freeze([
6401
6454
  "input",
6402
6455
  "tab",
6403
6456
  "bookingStep",
6404
- "dialog"
6457
+ "dialog",
6458
+ "cartBar",
6459
+ "planCard",
6460
+ "planReasonLabel",
6461
+ "planWash",
6462
+ "planChip"
6405
6463
  ]);
6464
+ var THEME_SLOT_KEYS_BY_SLOT = Object.freeze({
6465
+ planReasonLabel: Object.freeze(["textColor"]),
6466
+ planWash: Object.freeze(["backgroundColor"]),
6467
+ planChip: Object.freeze(["backgroundColor"])
6468
+ });
6406
6469
  var SLOT_MIN_CONTRAST = 4.5;
6407
6470
  var EMPTY = Object.freeze({});
6408
6471
  function isSlotName(value) {
@@ -6420,13 +6483,22 @@ function parseThemeSlots(json) {
6420
6483
  let any = false;
6421
6484
  for (const [name, raw] of Object.entries(json)) {
6422
6485
  if (!isSlotName(name) || raw === null || typeof raw !== "object") continue;
6423
- const slot = parseSlot(raw);
6486
+ const parsed = parseSlot(raw);
6487
+ if (parsed === null) continue;
6488
+ const slot = restrictSlotKeys(name, parsed);
6424
6489
  if (slot === null) continue;
6425
6490
  out[name] = slot;
6426
6491
  any = true;
6427
6492
  }
6428
6493
  return any ? Object.freeze(out) : null;
6429
6494
  }
6495
+ function restrictSlotKeys(name, slot) {
6496
+ const allowed = THEME_SLOT_KEYS_BY_SLOT[name];
6497
+ if (allowed === void 0) return slot;
6498
+ const out = {};
6499
+ for (const key of allowed) if (slot[key] !== void 0) out[key] = slot[key];
6500
+ return Object.keys(out).length === 0 ? null : Object.freeze(out);
6501
+ }
6430
6502
  function pick(raw, snake, camel) {
6431
6503
  return raw[snake] !== void 0 ? raw[snake] : raw[camel];
6432
6504
  }
@@ -6458,7 +6530,9 @@ var DECORATIVE_EDGE_SLOTS = /* @__PURE__ */ new Set([
6458
6530
  "banner",
6459
6531
  "header",
6460
6532
  "dialog",
6461
- "bookingStep"
6533
+ "bookingStep",
6534
+ "cartBar",
6535
+ "planCard"
6462
6536
  ]);
6463
6537
  function sameColor(a, b) {
6464
6538
  const left = parseColor(a);
@@ -7246,7 +7320,12 @@ function slotGrounds(c) {
7246
7320
  input: [c.surface, c.composerFill, c.surfaceCream, c.surfaceSubtle],
7247
7321
  tab: [c.surface, c.background],
7248
7322
  bookingStep: [c.surface, c.background],
7249
- dialog: [c.surface]
7323
+ dialog: [c.surface],
7324
+ cartBar: [c.brand],
7325
+ planCard: [c.surface],
7326
+ planReasonLabel: [c.surface],
7327
+ planWash: [c.surface],
7328
+ planChip: [c.surface]
7250
7329
  };
7251
7330
  }
7252
7331
  function slotSurrounds(c) {
@@ -7260,6 +7339,11 @@ function slotSurrounds(c) {
7260
7339
  };
7261
7340
  }
7262
7341
 
7342
+ // src/registry/sdk/client/wire/read.ts
7343
+ function isRecord(value) {
7344
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7345
+ }
7346
+
7263
7347
  // src/registry/sdk/client/theme/appearance.ts
7264
7348
  var APPEARANCE_PRESET_NAMES = Object.freeze(["everfur", "minimal", "night"]);
7265
7349
  var APPEARANCE_PRESETS = Object.freeze({
@@ -7272,9 +7356,6 @@ var APPEARANCE_SIZE_RANGES = Object.freeze({
7272
7356
  borderRadius: Object.freeze({ min: 0, max: 32, default: 14 }),
7273
7357
  spacingUnit: Object.freeze({ min: 3, max: 6, default: 4 })
7274
7358
  });
7275
- function isRecord(value) {
7276
- return value !== null && typeof value === "object" && !Array.isArray(value);
7277
- }
7278
7359
  function isPreset(value) {
7279
7360
  return typeof value === "string" && APPEARANCE_PRESET_NAMES.includes(value.trim().toLowerCase());
7280
7361
  }
@@ -7363,6 +7444,73 @@ function expandAppearance(appearance) {
7363
7444
  }
7364
7445
  return Object.keys(out).length === 0 ? null : Object.freeze(out);
7365
7446
  }
7447
+ var PRESENTATION_WIRE_NAMES = Object.freeze({
7448
+ chatAnswerStyle: "chat_answer_style",
7449
+ chatHistoryStyle: "chat_history_style",
7450
+ chatTopCard: "chat_top_card",
7451
+ chatFollowUpCount: "chat_follow_up_count",
7452
+ chatFollowUpsExcludeTelevet: "chat_follow_ups_exclude_televet",
7453
+ chatComposerMic: "chat_composer_mic",
7454
+ chatComposerUpload: "chat_composer_upload",
7455
+ safetyDisclaimerPlacement: "safety_disclaimer_placement",
7456
+ healthPlanLayout: "health_plan_layout",
7457
+ recordsTopRiskLine: "records_top_risk_line",
7458
+ recordsClearResultsFilter: "records_clear_results_filter",
7459
+ chatComposerStyle: "chat_composer_style",
7460
+ chatComposerPlaceholder: "chat_composer_placeholder",
7461
+ chatHistoryBar: "chat_history_bar",
7462
+ chatGeneralBanner: "chat_general_banner",
7463
+ chatSendButton: "chat_send_button",
7464
+ chatTextingAsk: "chat_texting_ask"
7465
+ });
7466
+ var FIELDS = Object.keys(PRESENTATION_WIRE_NAMES);
7467
+ var PRESENTATION_LOCK = "presentation";
7468
+ var PRESENTATION_LOCK_PREFIX = "presentation.";
7469
+ function isPresentationLockName(name) {
7470
+ if (name === PRESENTATION_LOCK) return true;
7471
+ if (!name.startsWith(PRESENTATION_LOCK_PREFIX)) return false;
7472
+ const field = name.slice(PRESENTATION_LOCK_PREFIX.length);
7473
+ return Object.values(PRESENTATION_WIRE_NAMES).includes(field);
7474
+ }
7475
+ var ENUMS = {
7476
+ chatAnswerStyle: ["bubbles", "cards"],
7477
+ chatHistoryStyle: ["drawer", "sheet"],
7478
+ chatTopCard: ["none", "focus"],
7479
+ safetyDisclaimerPlacement: ["composer", "answer_footer"],
7480
+ healthPlanLayout: ["standard", "focus_plan"],
7481
+ chatComposerStyle: ["standard", "compact"],
7482
+ chatComposerPlaceholder: ["generic", "pet_name"],
7483
+ chatHistoryBar: ["pinned", "scroll"],
7484
+ chatSendButton: ["always_dark", "dim_when_empty"]
7485
+ };
7486
+ var BOOLS = /* @__PURE__ */ new Set([
7487
+ "chatFollowUpsExcludeTelevet",
7488
+ "chatComposerMic",
7489
+ "chatComposerUpload",
7490
+ "recordsTopRiskLine",
7491
+ "recordsClearResultsFilter",
7492
+ "chatGeneralBanner",
7493
+ "chatTextingAsk"
7494
+ ]);
7495
+ function parseField(field, value) {
7496
+ if (value === null || value === void 0) return void 0;
7497
+ const allowed = ENUMS[field];
7498
+ if (allowed !== void 0) return typeof value === "string" && allowed.includes(value) ? value : void 0;
7499
+ if (BOOLS.has(field)) return typeof value === "boolean" ? value : void 0;
7500
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 3 ? value : void 0;
7501
+ }
7502
+ function parsePresentation(raw) {
7503
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
7504
+ const source = raw;
7505
+ const out = {};
7506
+ for (const field of FIELDS) {
7507
+ const wire = PRESENTATION_WIRE_NAMES[field];
7508
+ const value = Object.prototype.hasOwnProperty.call(source, wire) ? source[wire] : source[field];
7509
+ const parsed = parseField(field, value);
7510
+ if (parsed !== void 0) out[field] = parsed;
7511
+ }
7512
+ return Object.keys(out).length === 0 ? null : Object.freeze(out);
7513
+ }
7366
7514
 
7367
7515
  // src/registry/sdk/client/theme/fontSources.ts
7368
7516
  var MAX_FONT_SOURCES = 4;
@@ -7399,15 +7547,12 @@ function familyName(value) {
7399
7547
  if (trimmed.length === 0 || trimmed.length > FAMILY_MAX_LENGTH) return null;
7400
7548
  return /[\u0000-\u001F\u007F]/.test(trimmed) ? null : trimmed;
7401
7549
  }
7402
- function isRecord2(value) {
7403
- return value !== null && typeof value === "object" && !Array.isArray(value);
7404
- }
7405
7550
  function pick2(raw, ...keys) {
7406
7551
  for (const key of keys) if (raw[key] !== void 0 && raw[key] !== null) return raw[key];
7407
7552
  return void 0;
7408
7553
  }
7409
7554
  function parseFontSource(raw) {
7410
- if (!isRecord2(raw)) return null;
7555
+ if (!isRecord(raw)) return null;
7411
7556
  const family = familyName(raw["family"]);
7412
7557
  if (family === null) return null;
7413
7558
  const srcRaw = pick2(raw, "src");
@@ -7498,6 +7643,7 @@ function lockedFieldsOf(b) {
7498
7643
  }
7499
7644
  function isThemeLockName(name) {
7500
7645
  if (name === "hide_powered_by" || LOCKABLE_THEME_FIELDS.includes(name)) return true;
7646
+ if (isPresentationLockName(name)) return true;
7501
7647
  return name.startsWith(SLOT_LOCK_PREFIX) && THEME_SLOT_NAMES.includes(name.slice(SLOT_LOCK_PREFIX.length));
7502
7648
  }
7503
7649
  function parseClientBranding(json) {
@@ -7538,6 +7684,7 @@ function parseFlat(raw) {
7538
7684
  slots: parseThemeSlots(pick3(raw, "slots")),
7539
7685
  accessibilityMaxFontScale: parseMaxFontScale(pick3(raw, "accessibility_max_font_scale", "accessibilityMaxFontScale")),
7540
7686
  lockedFields: parseLockedFields(pick3(raw, "locked_fields", "lockedFields")),
7687
+ presentation: parsePresentation(pick3(raw, "presentation")),
7541
7688
  schemaVersion: parseSchemaVersion(pick3(raw, "schema_version", "schemaVersion")),
7542
7689
  backgroundColor: parseColor(pick3(raw, "background_color", "backgroundColor")),
7543
7690
  backgroundColorDark: parseColor(pick3(raw, "background_color_dark", "backgroundColorDark")),
@@ -7633,6 +7780,9 @@ function parseSchemaVersion(value) {
7633
7780
  function toWireName(name) {
7634
7781
  const trimmed = name.trim();
7635
7782
  if (trimmed.startsWith(SLOT_LOCK_PREFIX)) return trimmed;
7783
+ if (trimmed.startsWith(PRESENTATION_LOCK_PREFIX)) {
7784
+ return PRESENTATION_LOCK_PREFIX + trimmed.slice(PRESENTATION_LOCK_PREFIX.length).replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
7785
+ }
7636
7786
  return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
7637
7787
  }
7638
7788
  function parseLockedFields(value) {
@@ -12844,7 +12994,7 @@ var FRAME_CHAT_VET_NOTE = " A frame takes no onFindVet or onVetPrep: functions d
12844
12994
  var RECORDS_DEPTH_SENTENCE = " Lab markers, share links, the record PDF link, fact edits and the signature gallery need the platform flag partner.records_full_depth_enabled; while it is off for your tenant the SDK hides them, so their absence is not a defect in your integration.";
12845
12995
  var RECORDS_SURFACE_NOTE = Object.freeze({
12846
12996
  native: ` EverfurRecords is the app's records flow: it opens on the pet's dashboard and owns its own stack (the hardware back key pops it on React Native), every screen is also exported by name for your own navigator (the mount-records-screens step names them), and initialScreen={{ name: 'request', requestId }} opens a request directly. The mount passes petName={selectedPet.name} for headings such as "{petName}'s lab trends".` + RECORDS_DEPTH_SENTENCE,
12847
- web: ` The mount is ${WEB_RECORDS_SURFACE}, written into the file: it renders EverfurRecordsPage, the SDK's page-shaped root ported from Everfur's own web records page (one scrolling document with the pet's requests), and opens what the page links to (the full record with its vaccinations, the timeline, and an upload on an empty page) in the records flow EverfurRecords in the same place, whose back from its first screen returns to the page, so moving between them stays in place and adds no route to your app. The share link and the record PDF still open in a new tab, the SDK's web default, until the SDK changes it. The page holds no clinic request of its own: a plan that also asks for records-clinic mounts that surface beside it. When the flow sends a clinic request (one clinic or a batch), or the member opens their records from a published request, it lands on its own dashboard, whose back returns to the page. The mount passes petName={selectedPet.name} for headings such as "{petName}'s lab trends".` + RECORDS_DEPTH_SENTENCE
12997
+ web: ` The mount is ${WEB_RECORDS_SURFACE}, written into the file: it renders EverfurRecordsPage, the SDK's page-shaped root ported from Everfur's own web records page (one scrolling document with the pet's requests), and opens what the page links to (the full record with its vaccinations, the timeline, and an upload on an empty page) in the records flow EverfurRecords in the same place, whose back from its first screen returns to the page, so moving between them stays in place and adds no route to your app. The share link and the record PDF still open in a new tab, the SDK's web default, until the SDK changes it. The page also opens its clinic-request flow with consent and signature. A plan that also asks for records-clinic mounts its dedicated request surface beside the page. When the flow sends a clinic request (one clinic or a batch), or the member opens their records from a published request, it lands on its own dashboard, whose back returns to the page. The mount passes petName={selectedPet.name} for headings such as "{petName}'s lab trends".` + RECORDS_DEPTH_SENTENCE
12848
12998
  });
12849
12999
  function recordsScreensStep(surface) {
12850
13000
  const web = surface === "web";
@@ -13823,8 +13973,8 @@ function planIntegration(input) {
13823
13973
  // src/registry/sdk/client/contract/contract.generated.ts
13824
13974
  var CONTRACT_SOURCE = Object.freeze({
13825
13975
  digestAlgorithm: "sha256",
13826
- digest: "860245ebc1d82ec87e76bd5d9eb33d845fddc73ab1998b9e7b67457defe81f48",
13827
- generatedAt: "2026-10-07T05:52:37Z",
13976
+ digest: "f2c258aa21d5f24e8b1056db2114c3b4e5317c82119d86022fde295b059b4bfe",
13977
+ generatedAt: "2026-10-31T06:47:06Z",
13828
13978
  capabilitySchemaVersion: 1,
13829
13979
  errorSchemaVersion: 1
13830
13980
  });
@@ -13851,6 +14001,8 @@ var CONTRACT_RETRYABILITY = Object.freeze([
13851
14001
  Object.freeze({ wireCode: "attachment_unreadable", envelope: "http_envelope", httpStatus: 400, retryable: false }),
13852
14002
  Object.freeze({ wireCode: "authExpired", envelope: "http_envelope", httpStatus: 401, retryable: true }),
13853
14003
  Object.freeze({ wireCode: "authRejected", envelope: "http_envelope", httpStatus: 401, retryable: false }),
14004
+ Object.freeze({ wireCode: "catalog_empty_refused", envelope: "http_envelope", httpStatus: 409, retryable: false }),
14005
+ Object.freeze({ wireCode: "catalog_shrink_refused", envelope: "http_envelope", httpStatus: 409, retryable: false }),
13854
14006
  Object.freeze({ wireCode: "consent_invalid", envelope: "http_envelope", httpStatus: 422, retryable: false }),
13855
14007
  Object.freeze({ wireCode: "consent_required", envelope: "http_envelope", httpStatus: 422, retryable: false }),
13856
14008
  Object.freeze({ wireCode: "consent_scope_wrong_route", envelope: "http_envelope", httpStatus: 400, retryable: false }),
@@ -13875,6 +14027,7 @@ var CONTRACT_RETRYABILITY = Object.freeze([
13875
14027
  Object.freeze({ wireCode: "invalid_request", envelope: "oauth_error", httpStatus: 400, retryable: false }),
13876
14028
  Object.freeze({ wireCode: "invalid_scope", envelope: "oauth_error", httpStatus: 400, retryable: false }),
13877
14029
  Object.freeze({ wireCode: "invalid_target", envelope: "oauth_error", httpStatus: 400, retryable: false }),
14030
+ Object.freeze({ wireCode: "linked_account_read_only", envelope: "http_envelope", httpStatus: 409, retryable: false }),
13878
14031
  Object.freeze({ wireCode: "mcp_connection_not_found", envelope: "http_envelope", httpStatus: 404, retryable: false }),
13879
14032
  Object.freeze({ wireCode: "mcp_request_conflict", envelope: "http_envelope", httpStatus: 409, retryable: false }),
13880
14033
  Object.freeze({ wireCode: "mcp_request_gone", envelope: "http_envelope", httpStatus: 410, retryable: false }),
@@ -13911,6 +14064,7 @@ var CONTRACT_RETRYABILITY = Object.freeze([
13911
14064
  Object.freeze({ wireCode: "unrestrictedKeyRequired", envelope: "http_envelope", httpStatus: 403, retryable: false }),
13912
14065
  Object.freeze({ wireCode: "unsupported_grant_type", envelope: "oauth_error", httpStatus: 400, retryable: false }),
13913
14066
  Object.freeze({ wireCode: "unsupported_response_type", envelope: "oauth_error", httpStatus: 302, retryable: false }),
14067
+ Object.freeze({ wireCode: "user_ref_invalid", envelope: "http_envelope", httpStatus: 400, retryable: false }),
13914
14068
  Object.freeze({ wireCode: "verify_mint_rate_limited", envelope: "http_envelope", httpStatus: 429, retryable: true }),
13915
14069
  Object.freeze({ wireCode: "verify_mint_refused", envelope: "http_envelope", httpStatus: 403, retryable: false }),
13916
14070
  Object.freeze({ wireCode: "verify_mint_unavailable", envelope: "http_envelope", httpStatus: 503, retryable: true }),
@@ -13969,6 +14123,9 @@ var NORMALIZED_FOLD = Object.freeze({
13969
14123
  // revoke, decided on the key's shape alone. A partner_server 403 that no retry or fresh token fixes, so it
13970
14124
  // folds with `insufficientCapability`. It never reaches a device runtime.
13971
14125
  unrestrictedKeyRequired: "accessDenied",
14126
+ // the session mint and revoke reject a malformed user_ref (a partner_server 400 checked before any
14127
+ // credential work). Fixing the user_ref is the only cure, so it is a non-retryable input fault.
14128
+ user_ref_invalid: "validationFailed",
13972
14129
  // the partner events server surface (POST/GET /partners/events). Every one is a non-retryable input
13973
14130
  // fault, so each folds to validationFailed; the 413 matches the ValidationException the rest of the API
13974
14131
  // answers for an oversized body. `idempotency_key_reused` is the same client bug as
@@ -14158,7 +14315,18 @@ var NORMALIZED_FOLD = Object.freeze({
14158
14315
  // `already_mapped`, so a client that timed out learns the pet id instead of a conflict.
14159
14316
  partner_visit_owner_only: "accessDenied",
14160
14317
  partner_visit_link_conflict: "conflict",
14161
- partner_visit_pet_already_mapped: "conflict"
14318
+ partner_visit_pet_already_mapped: "conflict",
14319
+ // The 409 a write gets when the member's Everfur account is linked to this partner read-only. On the wire it
14320
+ // is `ConflictException` with this token as `reason_code`, and `isLinkedAccountReadOnly` already keeps it on
14321
+ // `conflict` (an `accessDenied` would read as a consent or plan gate), so the registered code folds the same.
14322
+ linked_account_read_only: "conflict",
14323
+ // The partner catalog replace's two guards (PUT /partners/catalog/products), read off `reason_code` on a
14324
+ // `ConflictException` 409: an empty list, or one that would deactivate most of the active products, sent
14325
+ // without `confirm_empty` or `confirm_shrink`. NOTHING is written. They fold with the envelope's
14326
+ // ConflictException, the reading `src/server/catalog.ts` (CATALOG_REASONS) already gives them, and that table
14327
+ // keeps both non-retryable. Server to server only; neither reaches a device runtime.
14328
+ catalog_empty_refused: "conflict",
14329
+ catalog_shrink_refused: "conflict"
14162
14330
  });
14163
14331
  var CONTRACT_ERROR_ROWS = Object.freeze(
14164
14332
  CONTRACT_RETRYABILITY.map(
@@ -14326,16 +14494,16 @@ function userFacingError(code) {
14326
14494
  var MANIFEST_default = {
14327
14495
  sdk: {
14328
14496
  name: "@everfur/sdk",
14329
- version: "0.11.0"
14497
+ version: "0.17.0"
14330
14498
  },
14331
14499
  files: [
14332
14500
  {
14333
14501
  path: "client/contract/contract.generated.ts",
14334
- sha256: "7d0a933511698d009787ae98833f9ac4be12f49b4157d710bdff3dac758f4a92"
14502
+ sha256: "dbfc4cc268c85c1c6177a4772a08cadd75c551f22dfe995f48b9ebdcc0df3731"
14335
14503
  },
14336
14504
  {
14337
14505
  path: "client/errors/EverfurError.ts",
14338
- sha256: "3465877ba734750fd8985d9c8c02ab3d1188f9dd19a9e1c3ecf8cc86d6ac5806"
14506
+ sha256: "82c84b6152adb24ec0c78fac93579e16e1e24d3584aa38a6f5b5e6ca2699e382"
14339
14507
  },
14340
14508
  {
14341
14509
  path: "client/errors/codes.ts",
@@ -14343,7 +14511,7 @@ var MANIFEST_default = {
14343
14511
  },
14344
14512
  {
14345
14513
  path: "client/errors/contract.ts",
14346
- sha256: "eb68d4729cf54c7d6935096cef1372cbdbfbc34f73b7b5b436302506a5204cc7"
14514
+ sha256: "b7aa7fed5f456a9a299f99ff49bdc594e83581e2bdf7b3ee4f683fdcb2ab7ba9"
14347
14515
  },
14348
14516
  {
14349
14517
  path: "client/theme/adjustments.ts",
@@ -14351,11 +14519,11 @@ var MANIFEST_default = {
14351
14519
  },
14352
14520
  {
14353
14521
  path: "client/theme/appearance.ts",
14354
- sha256: "fe9db62840ed13a43cb51066b19220d4552e8b2c51f117c8c62d093cfa677009"
14522
+ sha256: "1e045809a1944ae09d98f614a3d6eab43bb8db463589f4f1cef5aa3fd281cc08"
14355
14523
  },
14356
14524
  {
14357
14525
  path: "client/theme/branding.ts",
14358
- sha256: "15d9c3c725e7daf08ad6209101346381698b4dc85257c92a46b08a9ff77ea49b"
14526
+ sha256: "bd886ecce5ea14d3f00815a972af7691120e72d383af542e3d4050fa17e46da8"
14359
14527
  },
14360
14528
  {
14361
14529
  path: "client/theme/color.ts",
@@ -14367,7 +14535,7 @@ var MANIFEST_default = {
14367
14535
  },
14368
14536
  {
14369
14537
  path: "client/theme/fontSources.ts",
14370
- sha256: "69bbe37f7ef1d51f00b988af67b0b0e17baa84e87d32a405e931e0a8028ac54b"
14538
+ sha256: "c734b1ec50b8615653b7d027534a264e11defe2892397c41bcf88285e6a3a699"
14371
14539
  },
14372
14540
  {
14373
14541
  path: "client/theme/globals.ts",
@@ -14381,21 +14549,29 @@ var MANIFEST_default = {
14381
14549
  path: "client/theme/input.ts",
14382
14550
  sha256: "cc601aed813c6f5ae61822ee18cd717f0b9fa1fba5b743d63c6edfec0f0bc2e2"
14383
14551
  },
14552
+ {
14553
+ path: "client/theme/presentation.ts",
14554
+ sha256: "af152d2acce2383e7382061d2bc6b2d10c3c04df8348fc462636cb72445882e0"
14555
+ },
14384
14556
  {
14385
14557
  path: "client/theme/resolve.ts",
14386
14558
  sha256: "cad427919d7371f8f9ea7cc32b98ff9dd9454a9123bc73d345bfaf80952c9cae"
14387
14559
  },
14388
14560
  {
14389
14561
  path: "client/theme/slotGrounds.ts",
14390
- sha256: "c40192ff1793d44e9967892565827b27f8800dffab9d9a77b9c27e7399fc0a61"
14562
+ sha256: "a80402d0c572e1ca5fc77f378b171bbd53fa7c37127b6693d1ab0d6b660c3df2"
14391
14563
  },
14392
14564
  {
14393
14565
  path: "client/theme/slots.ts",
14394
- sha256: "47105b734b77269949db05d8014f3b0eb2a2171958343866adb5421615d86cd9"
14566
+ sha256: "64c108b2751ac28b48a7b837b25271a28058e93be32ee241b397c0f7df6b5d84"
14395
14567
  },
14396
14568
  {
14397
14569
  path: "client/theme/tokens.ts",
14398
14570
  sha256: "f9446c1cb689ea0af89c3289f7c8efa8330ca21a8710cdd8affa4fb1cc4ffd8e"
14571
+ },
14572
+ {
14573
+ path: "client/wire/read.ts",
14574
+ sha256: "fd03f0123d2ee1bf1ede61d5a114efd6dfe68b44b9329796ba17e2717174eb11"
14399
14575
  }
14400
14576
  ]
14401
14577
  };
@@ -14779,7 +14955,7 @@ function suggestCodes(query, codes) {
14779
14955
  near.sort((left, right) => left.distance - right.distance || (left.code < right.code ? -1 : 1));
14780
14956
  return Object.freeze([...exact, ...contains.sort(), ...near.map((entry) => entry.code)].slice(0, MAX_SUGGESTIONS));
14781
14957
  }
14782
- var SECRET_LITERAL = /\b(sk_partner_|sk_egress_)[A-Za-z0-9]{16,}/;
14958
+ var SECRET_LITERAL = /\b(sk_partner_|rk_partner_|sk_egress_)[A-Za-z0-9]{16,}/;
14783
14959
  var SECRET_ENV_NAME = "EVERFUR_PARTNER_SECRET_KEY";
14784
14960
  var PUBLIC_SECRET_NAME = /\b(NEXT_PUBLIC_|VITE_|EXPO_PUBLIC_)[A-Z0-9_]*SECRET[A-Z0-9_]*/;
14785
14961
  var API_BASE_URL_LINE = /^\s*(?:export\s+)?([A-Z0-9_]*EVERFUR_API_BASE_URL)\s*=\s*["']?([^"'\s#]+)/gm;
@@ -15656,7 +15832,7 @@ function anonymousIdentity(options) {
15656
15832
  return {
15657
15833
  auth: null,
15658
15834
  step: step5("anonymous-identity", title, "SKIP", `no anonymous identity to verify with: ${PARTNER_KEY.envVar} is not set`, null, [
15659
- `export ${PARTNER_KEY.envVar} with your publishable key (${PARTNER_KEY.prefix}...)`
15835
+ `export ${PARTNER_KEY.envVar} with your publishable key (${publishableKeyShapes()})`
15660
15836
  ])
15661
15837
  };
15662
15838
  }
@@ -16483,6 +16659,8 @@ var REFUSAL_POLICY = Object.freeze({
16483
16659
  CHAT_NOT_GRANTED: { retryable: false, nextAction: "call_diagnose", docsPath: null },
16484
16660
  CONVERSATIONS_UNREADABLE: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16485
16661
  PRIOR_TURN_UNANSWERED: { retryable: true, nextAction: "wait_then_retry", docsPath: null },
16662
+ // the earlier turn's stored reply is the interrupted-stream sentinel: final, so the same key can never succeed
16663
+ PRIOR_TURN_INTERRUPTED: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16486
16664
  CONVERSATION_NOT_CREATED: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16487
16665
  SEND_FAILED: { retryable: "from_failure", nextAction: "from_failure", docsPath: "everfur://contract/errors" },
16488
16666
  DEADLINE_EXCEEDED: { retryable: true, nextAction: "retry", docsPath: null },
@@ -16497,6 +16675,43 @@ var REFUSAL_POLICY = Object.freeze({
16497
16675
  // hosted only: the connected tenant has no publishable key, or one of a shape no deployment issues. Its keys are
16498
16676
  // Everfur's to issue and nothing a developer exports reaches them, so the refusal is reported, never "fixed" locally
16499
16677
  TENANT_PUBLISHABLE_KEY_UNUSABLE: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16678
+ // the claims tools (claims-tools.ts). The sandbox tool reads the sandbox tenant's secret key from a local shell
16679
+ // only; the sandbox routes refuse a live key (sandbox_key_required) and answer 404 while switched off for the tenant
16680
+ CLAIMS_SERVER_KEY_UNAVAILABLE: { retryable: false, nextAction: "fix_environment", docsPath: null },
16681
+ CLAIMS_SERVER_KEY_MALFORMED: { retryable: false, nextAction: "fix_environment", docsPath: null },
16682
+ CLAIMS_SANDBOX_KEY_REQUIRED: { retryable: false, nextAction: "use_sandbox_tenant", docsPath: null },
16683
+ CLAIMS_SANDBOX_NOT_ENABLED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16684
+ CLAIMS_SANDBOX_CALL_FAILED: { retryable: "from_failure", nextAction: "from_failure", docsPath: null },
16685
+ CLAIMS_ARGUMENTS_INVALID: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16686
+ // everfur_verify_claims_receiver: the URL is not localhost or public https, the signing secret is not usable, or
16687
+ // the receiver failed a check (each failed check carries its own fix)
16688
+ CLAIMS_RECEIVER_URL_REFUSED: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16689
+ CLAIMS_WEBHOOK_SECRET_UNUSABLE: { retryable: false, nextAction: "fix_environment", docsPath: null },
16690
+ CLAIMS_RECEIVER_CHECKS_FAILED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16691
+ // the sandbox and verify claims tools on the Everfur-hosted server, which holds no local key or signing secret
16692
+ CLAIMS_TOOL_NOT_HOSTED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16693
+ // the inbound claims tools (claims-inbound-tools.ts): a mapping the checks refuse, an activation no person
16694
+ // confirmed, the inbound secret or URL not usable here, and samples that did not apply
16695
+ CLAIMS_MAPPING_INVALID: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16696
+ CLAIMS_MAPPING_CONFIRMATION_REQUIRED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16697
+ // activate_draft with no draft saved (the active mapping, if any, is named): a person saves and confirms a new one
16698
+ CLAIMS_MAPPING_DRAFT_MISSING: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16699
+ CLAIMS_INBOUND_SECRET_UNUSABLE: { retryable: false, nextAction: "fix_environment", docsPath: null },
16700
+ CLAIMS_INBOUND_URL_UNUSABLE: { retryable: false, nextAction: "fix_environment", docsPath: null },
16701
+ CLAIMS_INBOUND_SAMPLES_FAILED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16702
+ // create_endpoint: no person confirmed the one-time create, the tenant already has its endpoint, or the endpoint
16703
+ // was created and its URL or secret (shown once) could not be written to the env file
16704
+ CLAIMS_INBOUND_CREATE_CONFIRMATION_REQUIRED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16705
+ CLAIMS_INBOUND_ENDPOINT_EXISTS: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16706
+ CLAIMS_INBOUND_CREDENTIALS_NOT_WRITTEN: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16707
+ // the one-time and replacing sandbox actions: no person has confirmed yet (a local code was written, or none could
16708
+ // be), or the person declined when the client asked them
16709
+ CLAIMS_HUMAN_CONFIRMATION_REQUIRED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16710
+ CLAIMS_HUMAN_DECLINED: { retryable: false, nextAction: "report_to_developer", docsPath: null },
16711
+ // the sandbox claims tools: EVERFUR_API_BASE_URL names a host the secret key is not sent to
16712
+ CLAIMS_API_HOST_NOT_ALLOWED: { retryable: false, nextAction: "fix_environment", docsPath: null },
16713
+ // everfur_explain_claims_error
16714
+ UNKNOWN_CLAIMS_ERROR_CODE: { retryable: false, nextAction: "fix_arguments", docsPath: null },
16500
16715
  // any tool: a body threw instead of returning a document
16501
16716
  INTERNAL_ERROR: { retryable: false, nextAction: "report_to_developer", docsPath: null }
16502
16717
  });
@@ -16634,7 +16849,7 @@ function chooseWidgetAuth(env) {
16634
16849
  return {
16635
16850
  ok: false,
16636
16851
  outcome: errorOutcome("credential_missing", "no widget credential is configured", [
16637
- `export ${PARTNER_KEY.envVar} with your publishable key (${PARTNER_KEY.prefix}...)`,
16852
+ `export ${PARTNER_KEY.envVar} with your publishable key (${publishableKeyShapes()})`,
16638
16853
  `or export ${SESSION_TOKEN.envVar} with an existing session bearer to diagnose the signed path`
16639
16854
  ])
16640
16855
  };
@@ -16742,6 +16957,15 @@ var DIAGNOSE = "everfur_diagnose";
16742
16957
  var EXPLAIN = "everfur_explain_error";
16743
16958
  var SEND = "everfur_send_test_message";
16744
16959
  var SEARCH = "everfur_search_docs";
16960
+ var CLAIMS_PLAN = "everfur_plan_claims_integration";
16961
+ var CLAIMS_SANDBOX = "everfur_send_claims_test_events";
16962
+ var CLAIMS_VERIFY = "everfur_verify_claims_receiver";
16963
+ var CLAIMS_EXPLAIN = "everfur_explain_claims_error";
16964
+ var CLAIMS_PROPOSE = "everfur_propose_claims_mapping";
16965
+ var CLAIMS_SAVE = "everfur_save_claims_mapping";
16966
+ var CLAIMS_SETUP = "everfur_claims_inbound_signing_setup";
16967
+ var CLAIMS_SAMPLES = "everfur_send_claims_inbound_samples";
16968
+ var CLAIMS_INBOUND = [CLAIMS_SAVE, CLAIMS_SETUP, CLAIMS_SAMPLES];
16745
16969
  var TENANT_READS = [
16746
16970
  "everfur_get_tenant_status",
16747
16971
  "everfur_list_webhook_endpoints",
@@ -16762,12 +16986,12 @@ var MEANINGS = Object.freeze({
16762
16986
  nextAction: "Ask the developer each fact in error.details.missing_facts, then call everfur_plan_integration again with the same arguments plus those answers. Do not guess them."
16763
16987
  },
16764
16988
  PROJECT_SOURCE_REQUIRED: {
16765
- tools: [PLAN],
16989
+ tools: [PLAN, CLAIMS_PLAN],
16766
16990
  meaning: "Neither project_root nor project_details was passed, so there was no project to plan for.",
16767
16991
  nextAction: "Call again with project_details (the dependencies, package manager and file-presence markers) on a remote or hosted server, or project_root on a server that runs beside the project."
16768
16992
  },
16769
16993
  PROJECT_SOURCE_AMBIGUOUS: {
16770
- tools: [PLAN],
16994
+ tools: [PLAN, CLAIMS_PLAN],
16771
16995
  meaning: "Both project_root and project_details were passed, and the plan takes exactly one project source.",
16772
16996
  nextAction: "Call again with one of them: project_root on a server beside the project, project_details on a remote one."
16773
16997
  },
@@ -16792,23 +17016,23 @@ var MEANINGS = Object.freeze({
16792
17016
  nextAction: "Ask the developer which was meant: omit environment to plan for the connected tenant's own mode, or connect with a tenant of the mode the environment needs. On a local server, pass the environment of the key's tenant, or set EVERFUR_PARTNER_KEY to the key of the tenant meant."
16793
17017
  },
16794
17018
  UNKNOWN_PLAN_STEP: {
16795
- tools: [PLAN],
17019
+ tools: [PLAN, CLAIMS_PLAN],
16796
17020
  meaning: "A step id in steps is not a step of this plan. error.details.unknown lists the ids that are not, and error.details.steps every id the plan has.",
16797
17021
  nextAction: "Call again with the same arguments and plan_id, and steps taken from error.details.steps."
16798
17022
  },
16799
17023
  UNKNOWN_PLAN_PAGE: {
16800
- tools: [PLAN],
17024
+ tools: [PLAN, CLAIMS_PLAN],
16801
17025
  meaning: "The page asked for is not a page of this plan, or page and steps were both given. error.details.pages is how many pages the plan has.",
16802
17026
  nextAction: "Call again with the same arguments and plan_id, and page from 1 to error.details.pages, or with steps and no page."
16803
17027
  },
16804
17028
  PLAN_CHANGED: {
16805
- tools: [PLAN],
17029
+ tools: [PLAN, CLAIMS_PLAN],
16806
17030
  meaning: "The plan_id passed is not the plan these arguments produce now: the arguments differ from the call that returned it, the project changed in a way that changes a step (a command run or a file written from the plan can), or the contract changed. error.details carries both ids.",
16807
17031
  nextAction: "Call again with the same arguments and without plan_id, page and steps for the summary of the current plan, then fetch its pages with the plan_id it returns."
16808
17032
  },
16809
17033
  // shared wire configuration
16810
17034
  WIRE_NOT_CONFIGURED: {
16811
- tools: [PLAN, VERIFY, DIAGNOSE, EXPLAIN, SEND, SEARCH],
17035
+ tools: [PLAN, VERIFY, DIAGNOSE, EXPLAIN, SEND, SEARCH, CLAIMS_SANDBOX],
16812
17036
  meaning: "The server could not set up its connection to the Everfur API: the API base URL is missing or not usable. error.details names what is wrong.",
16813
17037
  nextAction: "Fix the server's environment as error.details says (EVERFUR_API_BASE_URL on a server you run), then call again."
16814
17038
  },
@@ -16939,6 +17163,12 @@ var MEANINGS = Object.freeze({
16939
17163
  meaning: "An earlier call with this idempotency_key already sent the message and no answer was stored for it; sending again would ask the question twice, so nothing was sent.",
16940
17164
  nextAction: "Wait for the earlier answer and call again with the same idempotency_key, or use a new idempotency_key to ask again."
16941
17165
  },
17166
+ PRIOR_TURN_INTERRUPTED: {
17167
+ tools: [SEND],
17168
+ // Copy reused verbatim: PRIOR_TURN_UNANSWERED's meaning and EMPTY_STREAM's remedy sentence.
17169
+ meaning: "An earlier call with this idempotency_key already sent the message and no answer was stored for it; sending again would ask the question twice, so nothing was sent.",
17170
+ nextAction: "To ask again, call with a new idempotency_key: the same key returns this turn instead of sending the message a second time."
17171
+ },
16942
17172
  CONVERSATION_NOT_CREATED: {
16943
17173
  tools: [SEND],
16944
17174
  meaning: "A conversation could not be opened: the create call failed, or returned no conversation_id.",
@@ -16985,6 +17215,122 @@ var MEANINGS = Object.freeze({
16985
17215
  meaning: "On the Everfur-hosted server: the connected tenant has no active publishable key, or one of a shape no deployment issues, so the call was not made. Everfur issues the tenant's keys; nothing the developer exports reaches them.",
16986
17216
  nextAction: "Tell the developer what error.details.how_to_fix says."
16987
17217
  },
17218
+ // the claims tools (claims-tools.ts)
17219
+ CLAIMS_SERVER_KEY_UNAVAILABLE: {
17220
+ tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17221
+ meaning: "The sandbox tenant's secret key is not set in the environment of the local shell this server runs from, so no sandbox route was called.",
17222
+ nextAction: "Tell the developer the sandbox tool needs the sandbox tenant's secret key exported from a local shell only, never in a committed MCP configuration."
17223
+ },
17224
+ CLAIMS_SERVER_KEY_MALFORMED: {
17225
+ tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17226
+ meaning: "The secret key set in the local shell is not of the shape a partner secret key has, so no sandbox route was called.",
17227
+ nextAction: "Tell the developer to check the key exported in that shell; the value is never shown."
17228
+ },
17229
+ CLAIMS_SANDBOX_KEY_REQUIRED: {
17230
+ tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17231
+ meaning: "The sandbox route answered 403 sandbox_key_required: the key is a live tenant's key, and the sandbox routes take only a sandbox tenant's.",
17232
+ nextAction: "Use the sandbox tenant's secret key, then call again."
17233
+ },
17234
+ CLAIMS_SANDBOX_NOT_ENABLED: {
17235
+ tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17236
+ meaning: "The sandbox route answered 404 with no code of its own: the sandbox webhook or claims-inbound routes are not switched on for this tenant or deployment, the endpoint_id names no endpoint of this tenant, or (inbound) the tenant has no claims portal or no inbound endpoint exists yet. The sandbox key can create the sandbox inbound endpoint once (everfur_claims_inbound_signing_setup, create_endpoint with confirm: true from a person); its inbound URL and first secret are shown once, at creation. Live inbound endpoints are set up by Everfur.",
17237
+ nextAction: "Check the endpoint_id with list_endpoints; when list_endpoints itself answers this, switching the routes on is a step Everfur holds. When an inbound route answers it and the routes are on, the sandbox endpoint may not exist yet: offer create_endpoint, and create it only when a person confirms."
17238
+ },
17239
+ CLAIMS_SANDBOX_CALL_FAILED: {
17240
+ tools: [CLAIMS_SANDBOX, ...CLAIMS_INBOUND],
17241
+ meaning: "A sandbox route failed on the wire or answered an error with a code (error.details.code), such as webhook_url_rejected, webhook_endpoint_limit_reached or webhook_test_rate_limited.",
17242
+ nextAction: `Explain error.details.code with everfur_explain_claims_error (not everfur_explain_error) when there is one; after a 429, wait for error.details.retry_after. ${FROM_FAILURE}`
17243
+ },
17244
+ CLAIMS_ARGUMENTS_INVALID: {
17245
+ tools: [CLAIMS_SANDBOX, CLAIMS_PROPOSE, ...CLAIMS_INBOUND],
17246
+ meaning: "The action lacks an argument it needs (error.details.arguments), or secret_env_file cannot take the signing secret. Nothing was created.",
17247
+ nextAction: "Call again with the arguments named in error.details.arguments."
17248
+ },
17249
+ CLAIMS_RECEIVER_URL_REFUSED: {
17250
+ tools: [CLAIMS_VERIFY],
17251
+ meaning: "receiver_url is neither http(s) on localhost or 127.0.0.1 nor a public https URL, so nothing was sent to it.",
17252
+ nextAction: "Call again with the receiver on localhost or on its public https URL."
17253
+ },
17254
+ CLAIMS_WEBHOOK_SECRET_UNUSABLE: {
17255
+ tools: [CLAIMS_VERIFY],
17256
+ meaning: "The endpoint signing secret the checks sign with is not set in this server's environment, or is not a whsec_ value, so nothing was sent.",
17257
+ nextAction: "Tell the developer to set the same whsec_ signing secret their receiver reads in the environment this server runs from."
17258
+ },
17259
+ CLAIMS_RECEIVER_CHECKS_FAILED: {
17260
+ tools: [CLAIMS_VERIFY],
17261
+ meaning: "The receiver failed at least one check. Each check in the result says what was expected, what came back and the fix.",
17262
+ nextAction: "Apply the fix of each FAIL check to the receiver, then run the checks again."
17263
+ },
17264
+ CLAIMS_TOOL_NOT_HOSTED: {
17265
+ tools: [CLAIMS_SANDBOX, CLAIMS_VERIFY, ...CLAIMS_INBOUND],
17266
+ meaning: "This claims tool runs only on an MCP server on the developer's own machine; the Everfur-hosted server holds no sandbox key and no signing secret for a tenant.",
17267
+ nextAction: "Tell the developer to run the tool from the local MCP server or the CLI."
17268
+ },
17269
+ CLAIMS_MAPPING_INVALID: {
17270
+ tools: [CLAIMS_SAVE],
17271
+ meaning: "The mapping does not pass the mapping checks (error.details.problems: a path, a transform, a limit, or pii_paths hiding a field the mapping reads), or the API refused to save or activate it. Nothing was saved or activated.",
17272
+ nextAction: "Fix each problem in the mapping (everfur_propose_claims_mapping can propose one again), then save again."
17273
+ },
17274
+ CLAIMS_MAPPING_CONFIRMATION_REQUIRED: {
17275
+ tools: [CLAIMS_SAVE],
17276
+ meaning: "activate_draft was called without confirm: true and the confirmation phrase the save answer gave, or the phrase does not match the current draft. Nothing was activated.",
17277
+ nextAction: "Show the developer the draft and its phrase; activate only when a person who read it types the phrase back. Never activate on your own."
17278
+ },
17279
+ CLAIMS_MAPPING_DRAFT_MISSING: {
17280
+ tools: [CLAIMS_SAVE],
17281
+ meaning: "activate_draft found no mapping draft saved: none was ever saved, or it was already activated (error.details.active_version names the active one). Nothing was activated.",
17282
+ nextAction: "To change the active mapping, save a new draft with save_draft, show it and its phrase to the developer, and activate only when a person who read it types the phrase back."
17283
+ },
17284
+ CLAIMS_INBOUND_SECRET_UNUSABLE: {
17285
+ tools: [CLAIMS_SAMPLES],
17286
+ meaning: "The inbound endpoint's shared secret is not set in this server's environment or in secret_env_file, or is not a whsec_ value, so nothing was sent.",
17287
+ nextAction: "Rotate the sandbox secret into a local env file with everfur_claims_inbound_signing_setup (rotate_secret: true), then pass that file as secret_env_file."
17288
+ },
17289
+ CLAIMS_INBOUND_URL_UNUSABLE: {
17290
+ tools: [CLAIMS_SAMPLES],
17291
+ meaning: "The sandbox inbound URL is not set in this server's environment or in secret_env_file, is malformed, or names another host than the configured Everfur API, so nothing was sent.",
17292
+ nextAction: "Tell the developer to set the inbound URL from where it was saved when the sandbox endpoint was created (shown once), on the same API host as EVERFUR_API_BASE_URL; with no endpoint yet, offer create_endpoint."
17293
+ },
17294
+ CLAIMS_INBOUND_CREATE_CONFIRMATION_REQUIRED: {
17295
+ tools: [CLAIMS_SETUP],
17296
+ meaning: "create_endpoint was called without confirm: true. Creating the sandbox inbound endpoint is a one-time action (its URL and secret are shown once, and no route deletes a sandbox endpoint), so a person decides it. Nothing was created.",
17297
+ nextAction: "Show the developer the signing config; call create_endpoint with confirm: true only when a person asks for it. Never confirm on your own."
17298
+ },
17299
+ CLAIMS_INBOUND_ENDPOINT_EXISTS: {
17300
+ tools: [CLAIMS_SETUP],
17301
+ meaning: "The create answered 409 endpoint_exists: this sandbox tenant already has its inbound endpoint, whose URL was shown once, at creation. Nothing was created.",
17302
+ nextAction: "Tell the developer to set EVERFUR_CLAIMS_INBOUND_URL from where they saved it, and offer rotate_secret for a new secret or rotate_token for a new URL."
17303
+ },
17304
+ CLAIMS_INBOUND_CREDENTIALS_NOT_WRITTEN: {
17305
+ tools: [CLAIMS_SETUP],
17306
+ meaning: "The sandbox inbound endpoint was created, but its URL or secret (error.details.url_written, secret_written) could not be written to secret_env_file, and the API shows them only once.",
17307
+ nextAction: "Tell the developer plainly: the endpoint exists; a lost secret is recovered with rotate_secret and a lost URL with rotate_token, each with a writable secret_env_file. Never create again."
17308
+ },
17309
+ CLAIMS_HUMAN_CONFIRMATION_REQUIRED: {
17310
+ tools: [CLAIMS_SANDBOX, CLAIMS_SAVE, CLAIMS_SETUP],
17311
+ meaning: "A person must confirm this one-time or replacing sandbox action, and this client cannot ask them directly, so a one-time code was written to a local file (error.details.code_file, mode 600) and printed on the server's stderr. Nothing was done.",
17312
+ nextAction: "Tell the developer the file path and ask them to type the code back only if they want the action; call again with confirmation_code set to what they typed. Never open the file yourself."
17313
+ },
17314
+ CLAIMS_HUMAN_DECLINED: {
17315
+ tools: [CLAIMS_SANDBOX, CLAIMS_SAVE, CLAIMS_SETUP],
17316
+ meaning: "The client asked the person to confirm the action, and they declined or cancelled. Nothing was done.",
17317
+ nextAction: "Do not retry on your own; ask the developer what they want changed."
17318
+ },
17319
+ CLAIMS_API_HOST_NOT_ALLOWED: {
17320
+ tools: [CLAIMS_SANDBOX, CLAIMS_PROPOSE, ...CLAIMS_INBOUND],
17321
+ meaning: "EVERFUR_API_BASE_URL names a host other than api.everfur.com, api-staging.everfur.com or this machine, so the secret key is not sent to it. Nothing was sent.",
17322
+ nextAction: "Tell the developer to point EVERFUR_API_BASE_URL at the Everfur API, or to set EVERFUR_ALLOW_CUSTOM_API_HOST=1 in the shell for an Everfur API they trust."
17323
+ },
17324
+ CLAIMS_INBOUND_SAMPLES_FAILED: {
17325
+ tools: [CLAIMS_SAMPLES],
17326
+ meaning: "At least one sample did not end applied or duplicate, or a check failed. Each result carries its reason code and the fix.",
17327
+ nextAction: "Apply each result's fix (the mapping, the signing or the sample), then send the samples again."
17328
+ },
17329
+ UNKNOWN_CLAIMS_ERROR_CODE: {
17330
+ tools: [CLAIMS_EXPLAIN],
17331
+ meaning: "The code is not a Claims API code, a webhook delivery state or a profile import code. error.details.near_misses lists close spellings.",
17332
+ nextAction: "Check the code was copied exactly; when it was, say it is unknown."
17333
+ },
16988
17334
  // any tool
16989
17335
  INTERNAL_ERROR: {
16990
17336
  tools: ["any tool"],
@@ -17232,7 +17578,7 @@ var SDK_SUB_ENUMS = Object.freeze([
17232
17578
  },
17233
17579
  {
17234
17580
  name: "DictationErrorKind",
17235
- file: "src/web/chat/dictation/webSpeechDictation.ts",
17581
+ file: "src/react/chat/dictation/dictation.ts",
17236
17582
  declaration: "type",
17237
17583
  members: {
17238
17584
  permissionDenied: { meaning: "The browser refused microphone or speech recognition access (not-allowed, service-not-allowed).", retryable: false, nextAction: "The person allows the microphone in the browser's site settings." },
@@ -17393,4 +17739,4 @@ function resolveAfterRegistryMiss(code, registry) {
17393
17739
  return { kind: "unknown", suggestions: suggestCodes(code, knownCodes(registry)) };
17394
17740
  }
17395
17741
 
17396
- export { ADMIN_TOKEN, ALL_CAPABILITIES, API_BASE_URL_BY_ENVIRONMENT, API_PREFIX, BACKEND_LANGUAGE_QUESTION, BASE_URL_ENV_VAR, CAPABILITIES_TREE, CAPABILITY_QUESTION, CLI_VERSION, CREDENTIAL_SPECS, DEFAULT_TIMEOUT_MS, DIAGNOSTICS_PATH, DOCS_KEY, EMPTY_REGISTRY, ENVELOPE_SHAPE, ENVIRONMENTS, ERRORS_DOCUMENT_KEY, EVERFUR_LOADER_HOSTS, ExitCode, IDEMPOTENT_METHODS, IDENTITY_QUESTION, IDENTITY_TREE, MAX_TIMEOUT_MS, MIN_TIMEOUT_MS, MISSING_FACT_NAMES, NEXT_ACTIONS, NO_CONTRACT_CACHE, PARTNER_KEY, PARTNER_SECRET_KEY, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, PLATFORM_TREE, REASON_CODES, REDACTED, REFUSAL_POLICY, SCHEMAS, SESSION_MINT_TREE, SESSION_TOKEN, SURFACES, THEME_TOKEN_ORDER, TOOL_CODES, TransportError, VERIFY_IDENTITY_MODES, WEB_EMBEDDING_QUESTION, alsoInLines, apiUrl, blockedCapabilities, buildDecisionSpace, buildDiagnosisDocument, buildExplanationDocument, buildSupportBundle, checkTenantMode, chooseWidgetAuth, clampTimeout, contractUnavailableOutcome, countsAsNotOn, createApiClient, createContractProvider, createMemoryFileSystem, createRecordingClock, describeFailure, detectProject, detectTheme, detectThemeFromText, diagnoseFailure, diagnoseVerdict, diagnosis_v1_schema_default, digestOfProjection, digestsEqual, editDistance, entryFromRow, ephemeralCredential, errorCodeOf, errorOutcome, error_explanation_v1_schema_default, expandCapabilities, fail, failedResult, failureDetails, fetchContract, fetchTransport, isCorrelatableRequestId, isEverfurLoaderHost, isIdempotent, isJsonObject, isKnownReasonCode, isWorkspaceRootEvidence, knownCodes, loadDecisionSpace, loadDecisionSpaceFromContract, loadErrorRegistry, loadErrorRegistryFromContract, missingFactsFor, nextActionFor, nextActionFor2, nodeContractCache, nodeFileSystem, normalizeSurfaces, offlineDocument, parseDiagnostics, parseEnvironment, parseIdentityMode, parseLoaderUrl, parseOrigin, parseSurfaces, planIntegration, plan_v1_schema_default, plannableCapabilities, refusal, registryAlsoIn, renderExplanation, renderOffline, renderSupportBundle, resolveAfterRegistryMiss, resolveContractPath, resolveCredential, resolveEndpoint, resolveOffline, resolveWithoutRegistry, runVerification, succeed, suggestCodes, systemClock, themePropFromSource, toolCodeExplanation, toolCodeMeaning, uuidFromKey, validateContractFile, validateContractPublicEnvelope, validateContractText, validateDiagnosisDocument, validateErrorExplanationDocument, validatePlanDocument, validateSandboxCreateDocument, validateVerificationDocument, verification_v1_schema_default, verifyDigest, walkSingle, walkTree, withPrefix };
17742
+ export { ADMIN_TOKEN, ALLOW_CUSTOM_API_HOST_ENV_VAR, ALL_CAPABILITIES, API_BASE_URL_BY_ENVIRONMENT, API_BASE_URL_PLACEHOLDER, API_PREFIX, BACKEND_LANGUAGE_QUESTION, BASE_URL_ENV_VAR, CAPABILITIES_TREE, CAPABILITY_QUESTION, CLAIMS_INBOUND_SECRET, CLI_VERSION, CREDENTIAL_SPECS, DEFAULT_TIMEOUT_MS, DIAGNOSTICS_PATH, DOCS_KEY, EMPTY_REGISTRY, ENVELOPE_SHAPE, ENVIRONMENTS, ERRORS_DOCUMENT_KEY, EVERFUR_LOADER_HOSTS, ExitCode, IDEMPOTENT_METHODS, IDENTITY_QUESTION, IDENTITY_TREE, MAX_TIMEOUT_MS, MIN_TIMEOUT_MS, MISSING_FACT_NAMES, NEXT_ACTIONS, NO_CONTRACT_CACHE, PARTNER_KEY, PARTNER_SECRET_KEY, PLAN_DOCUMENT_KIND, PLAN_SCHEMA_VERSION, PLATFORM_TREE, REASON_CODES, REDACTED, REFUSAL_POLICY, SCHEMAS, SESSION_MINT_TREE, SESSION_TOKEN, SURFACES, THEME_TOKEN_ORDER, TOOL_CODES, TransportError, VERIFY_IDENTITY_MODES, WEBHOOK_PUBLIC_PATH, WEBHOOK_RECEIVER_PATH, WEBHOOK_SIGNING_SECRET, WEB_EMBEDDING_QUESTION, alsoInLines, apiUrl, blockedCapabilities, buildDecisionSpace, buildDiagnosisDocument, buildExplanationDocument, buildSupportBundle, checkTenantMode, chooseWidgetAuth, clampTimeout, contractUnavailableOutcome, countsAsNotOn, createApiClient, createContractProvider, createMemoryFileSystem, createRecordingClock, describeFailure, detectProject, detectTheme, detectThemeFromText, diagnoseFailure, diagnoseVerdict, diagnosis_v1_schema_default, digestOfProjection, digestsEqual, editDistance, entryFromRow, ephemeralCredential, errorCodeOf, errorOutcome, error_explanation_v1_schema_default, expandCapabilities, fail, failedResult, failureDetails, fetchContract, fetchTransport, hmacSha256, hmacSha256Hex, importPath, isCorrelatableRequestId, isEverfurLoaderHost, isIdempotent, isJsonObject, isKnownReasonCode, isWorkspaceRootEvidence, knownCodes, loadDecisionSpace, loadDecisionSpaceFromContract, loadErrorRegistry, loadErrorRegistryFromContract, missingFactsFor, nextActionFor, nextActionFor2, nodeContractCache, nodeFileSystem, normalizeSurfaces, offlineDocument, parseDiagnostics, parseEnvironment, parseIdentityMode, parseLoaderUrl, parseOrigin, parseSurfaces, planIntegration, plan_v1_schema_default, plannableCapabilities, refusal, registryAlsoIn, renderExplanation, renderOffline, renderSupportBundle, resolveAfterRegistryMiss, resolveContractPath, resolveCredential, resolveEndpoint, resolveOffline, resolveWithoutRegistry, runVerification, secretKeyHostProblem, succeed, suggestCodes, systemClock, themePropFromSource, toolCodeExplanation, toolCodeMeaning, uuidFromKey, validateContractFile, validateContractPublicEnvelope, validateContractText, validateDiagnosisDocument, validateErrorExplanationDocument, validatePlanDocument, validateSandboxCreateDocument, validateVerificationDocument, verification_v1_schema_default, verifyDigest, walkSingle, walkTree, webhookRouteFile, withPrefix };