@ouronet/talos-registry 2.1.0 → 2.2.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.
package/dist/index.d.ts CHANGED
@@ -16,6 +16,6 @@ export type { CallPlan } from "./plan.js";
16
16
  export { parseCapability, parseCapabilities, capabilityRecipe } from "./caps.js";
17
17
  export type { ParsedCapability, CapabilityRecipe } from "./caps.js";
18
18
  export { formatForType, formatDecimal, formatInteger, formatString, formatBool } from "./format.js";
19
- export { tooltipModel, tooltipModels, signatureRows, chainOf, isOffRegistryKey, isNativeKey, isPlaceholder, PLACEHOLDER, CHAIN_PALETTE, CHAIN_LABEL, CONSUMERS, STOA_SIGNATURES, KADENA_SIGNATURES, NATIVE_SIGNATURES } from "./tooltip.js";
20
- export type { TooltipModel, TooltipSlot, TooltipPreview, Chain, ConsumerIdentity } from "./tooltip.js";
19
+ export { tooltipModel, tooltipModels, signatureRows, chainOf, isOffRegistryKey, isNativeKey, isPlaceholder, PLACEHOLDER, CHAIN_PALETTE, CHAIN_LABEL, CONSUMERS, STOA_SIGNATURES, KADENA_SIGNATURES, NATIVE_SIGNATURES, paramRole, paramsByRole, unfilledFillable } from "./tooltip.js";
20
+ export type { TooltipModel, TooltipSlot, TooltipPreview, Chain, ConsumerIdentity, ParamRole } from "./tooltip.js";
21
21
  export type * from "./types.js";
package/dist/index.js CHANGED
@@ -15,4 +15,4 @@ export { parseCapability, parseCapabilities, capabilityRecipe } from "./caps.js"
15
15
  export { formatForType, formatDecimal, formatInteger, formatString, formatBool } from "./format.js";
16
16
  // THE TOOLTIP CANON. Shared implementation rather than a shared document -- see TOOLTIP-CANON.md
17
17
  // for why each rule exists, and `tooltip.ts` for the rules themselves.
18
- export { tooltipModel, tooltipModels, signatureRows, chainOf, isOffRegistryKey, isNativeKey, isPlaceholder, PLACEHOLDER, CHAIN_PALETTE, CHAIN_LABEL, CONSUMERS, STOA_SIGNATURES, KADENA_SIGNATURES, NATIVE_SIGNATURES } from "./tooltip.js";
18
+ export { tooltipModel, tooltipModels, signatureRows, chainOf, isOffRegistryKey, isNativeKey, isPlaceholder, PLACEHOLDER, CHAIN_PALETTE, CHAIN_LABEL, CONSUMERS, STOA_SIGNATURES, KADENA_SIGNATURES, NATIVE_SIGNATURES, paramRole, paramsByRole, unfilledFillable } from "./tooltip.js";
package/dist/tooltip.d.ts CHANGED
@@ -51,6 +51,14 @@ export interface TooltipSlot {
51
51
  isPreflightFed: boolean;
52
52
  /** false = never prefill into an input that can reach a signed transaction (guards). */
53
53
  prefillable: boolean;
54
+ /**
55
+ * The CALLER supplied this value; it is not a ghost.
56
+ *
57
+ * Tracked in the model rather than left to each renderer, because "is this the user's data or
58
+ * an example?" is the question every one of this module's bugs turned on, and two consumers
59
+ * answering it separately is two chances to answer it differently.
60
+ */
61
+ supplied: boolean;
54
62
  /** the registry's own note about this argument, when it has one. */
55
63
  note?: string;
56
64
  }
@@ -171,3 +179,30 @@ export declare function signatureRows(m: TooltipModel): {
171
179
  names: string[];
172
180
  types: string[];
173
181
  };
182
+ /**
183
+ * What KIND of thing a parameter holds.
184
+ *
185
+ * Pact types cannot answer this -- `patron`, `id`, `ats` and `swpair` are all `string`, and a
186
+ * value of the wrong kind in any of them type-checks, renders plausibly, and makes the preview
187
+ * succeed against the wrong entity. That is the defect class this whole module exists to prevent,
188
+ * and it has now produced four separate bugs.
189
+ */
190
+ export type ParamRole = "ouronet-account" | "kadena-account" | "token-id" | "dpof-id" | "ats-pool" | "swap-pool" | "other";
191
+ /** The role of a parameter name, or undefined when nothing is known about it. */
192
+ export declare function paramRole(name: string): ParamRole | undefined;
193
+ /** Every name this registry can classify, grouped. Useful for building a consumer's fill map. */
194
+ export declare function paramsByRole(): Record<ParamRole, string[]>;
195
+ /**
196
+ * RULE 7, as a check: which slots the consumer COULD have filled and did not.
197
+ *
198
+ * A slot qualifies when its role is known and the caller supplied no value for it. Those are the
199
+ * ones that silently show somebody else's real id -- `ats = "Auryndex-…"` on a SilverStoa button,
200
+ * an example account whose pool ledger is empty, a reward token rendered as "no live example".
201
+ *
202
+ * Placeholders and preflight-fed slots are NOT reported: the first is honestly unresolved and the
203
+ * second must not be invented. This answers "what did you leave on the table", not "what is
204
+ * missing".
205
+ *
206
+ * A conformant consumer asserts this is empty for every button it renders.
207
+ */
208
+ export declare function unfilledFillable(m: TooltipModel): TooltipSlot[];
package/dist/tooltip.js CHANGED
@@ -185,6 +185,7 @@ function offRegistryModel(key, kind, values, consumer) {
185
185
  isPreflightFed: false,
186
186
  // A guard is never prefillable, on any chain. Same rule, same reason.
187
187
  prefillable: type !== "guard",
188
+ supplied: values[name] !== undefined,
188
189
  })),
189
190
  // No preview, deliberately. Neither chain's `coin` has a reader that prices a call, so there
190
191
  // is no cost to show -- and a renderer must SAY that rather than leaving an empty panel,
@@ -257,6 +258,7 @@ export function tooltipModel(key, values = {}, consumer) {
257
258
  isPlaceholder,
258
259
  isPreflightFed,
259
260
  prefillable: u?.zbom !== false,
261
+ supplied: supplied !== undefined,
260
262
  note: ep.ghost.notes?.[p.name],
261
263
  };
262
264
  });
@@ -325,3 +327,81 @@ export function tooltipModels(keys, values = {}, consumer) {
325
327
  export function signatureRows(m) {
326
328
  return { names: m.slots.map((s) => s.name), types: m.slots.map((s) => s.type) };
327
329
  }
330
+ /**
331
+ * DERIVED FROM THE GHOST'S SHAPE, not from a hand-written list of 332 names.
332
+ *
333
+ * Hand-classifying the vocabulary would be the same act that produced the bugs: a human deciding
334
+ * that `ats` looks like a token because both are strings. The registry's ghosts were each resolved
335
+ * for their own parameter and READ FROM MAINNET, so the value's shape is evidence rather than
336
+ * opinion -- an Ouronet account is a glyph string, a pool is `Name-O136CBn22ncY`, a swap pair
337
+ * starts `W|`, a hibernated DPOF starts `H|`.
338
+ *
339
+ * A name whose ghost is the generic `"example"` gets NO role, and that is correct: nothing is
340
+ * known about it, so nothing should be inferred. Those render as visible placeholders.
341
+ */
342
+ const ROLE_PATTERNS = [
343
+ [/^k:/, "kadena-account"],
344
+ [/^[^\u0000-\u007F]\./, "ouronet-account"],
345
+ [/^W\|/, "swap-pool"],
346
+ [/^H\|/, "dpof-id"],
347
+ [/^[A-Za-z]+-O136CBn22ncY$/, "ats-pool"],
348
+ [/^[A-Z0-9]+-[A-Za-z0-9]{3}-[A-Za-z0-9]+$/, "token-id"],
349
+ ];
350
+ let ROLES = null;
351
+ function buildRoles() {
352
+ const out = new Map();
353
+ const reg = registry;
354
+ for (const coll of [reg.entrypoints, reg.previews]) {
355
+ for (const v of Object.values(coll)) {
356
+ const args = v?.ghost?.args ?? {};
357
+ for (const p of v?.params ?? []) {
358
+ if (p.type !== "string" || out.has(p.name))
359
+ continue;
360
+ const g = args[p.name];
361
+ if (typeof g !== "string" || g === "example")
362
+ continue;
363
+ for (const [re, role] of ROLE_PATTERNS)
364
+ if (re.test(g)) {
365
+ out.set(p.name, role);
366
+ break;
367
+ }
368
+ }
369
+ }
370
+ }
371
+ return out;
372
+ }
373
+ /** The role of a parameter name, or undefined when nothing is known about it. */
374
+ export function paramRole(name) {
375
+ if (!ROLES)
376
+ ROLES = buildRoles();
377
+ return ROLES.get(name);
378
+ }
379
+ /** Every name this registry can classify, grouped. Useful for building a consumer's fill map. */
380
+ export function paramsByRole() {
381
+ if (!ROLES)
382
+ ROLES = buildRoles();
383
+ const out = {};
384
+ for (const [n, r] of ROLES)
385
+ (out[r] ??= []).push(n);
386
+ for (const k of Object.keys(out))
387
+ out[k].sort();
388
+ return out;
389
+ }
390
+ /**
391
+ * RULE 7, as a check: which slots the consumer COULD have filled and did not.
392
+ *
393
+ * A slot qualifies when its role is known and the caller supplied no value for it. Those are the
394
+ * ones that silently show somebody else's real id -- `ats = "Auryndex-…"` on a SilverStoa button,
395
+ * an example account whose pool ledger is empty, a reward token rendered as "no live example".
396
+ *
397
+ * Placeholders and preflight-fed slots are NOT reported: the first is honestly unresolved and the
398
+ * second must not be invented. This answers "what did you leave on the table", not "what is
399
+ * missing".
400
+ *
401
+ * A conformant consumer asserts this is empty for every button it renders.
402
+ */
403
+ export function unfilledFillable(m) {
404
+ return m.slots.filter((s) => !s.supplied
405
+ && !s.isPlaceholder && !s.isPreflightFed
406
+ && paramRole(s.name) !== undefined);
407
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouronet/talos-registry",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "The Ouronet callable surface, generated from the deployed contracts. Supply values; never type a function name.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",