@ouronet/talos-registry 2.0.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/README.md +5 -3
- package/TOOLTIP-CANON.md +127 -17
- package/dist/data/registry.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/tooltip.d.ts +83 -7
- package/dist/tooltip.js +138 -11
- package/package.json +1 -1
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, STOA_SIGNATURES, KADENA_SIGNATURES, NATIVE_SIGNATURES } from "./tooltip.js";
|
|
20
|
-
export type { TooltipModel, TooltipSlot, TooltipPreview } 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, 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
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
/** The three worlds a tooltip can describe. See rule 4. */
|
|
2
|
+
export type Chain = "ouronet" | "stoa" | "kadena";
|
|
3
|
+
/**
|
|
4
|
+
* The canonical border colour per chain. USE THESE.
|
|
5
|
+
*
|
|
6
|
+
* Not styling: the colour tells a user which chain their money is on, and that vocabulary is
|
|
7
|
+
* shared between the applications that render it. Two apps teaching different meanings for the
|
|
8
|
+
* same colour is worse than neither using colour at all, because the user believes the first one
|
|
9
|
+
* they learned.
|
|
10
|
+
*
|
|
11
|
+
* ouronet blue the ouronet-ns surface -- priced, IGNIS, sponsored
|
|
12
|
+
* stoa gold StoaChain's own coin -- unpriced, no IGNIS, still sponsored
|
|
13
|
+
* kadena green a DIFFERENT CHAIN -- its own gas, its own balances
|
|
14
|
+
*
|
|
15
|
+
* Chosen from what was already in use rather than invented: gold is OuronetUI's STOA accent and
|
|
16
|
+
* blue its established `#3b82f6`; green is the app's existing success green, which is unused on
|
|
17
|
+
* any other tooltip surface and therefore free to carry this meaning.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CHAIN_PALETTE: Readonly<Record<Chain, string>>;
|
|
20
|
+
/** Human label for the chain, for the border-adjacent marker. */
|
|
21
|
+
export declare const CHAIN_LABEL: Readonly<Record<Chain, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* Who is drawing the tooltip -- rule 4b.
|
|
24
|
+
*
|
|
25
|
+
* Two applications render this, and a Codex panel can open over an OuronetUI page, which is
|
|
26
|
+
* exactly the case where "whose tooltip is this" is hardest to infer from chrome and most useful
|
|
27
|
+
* to state. The accent is the CONSUMER's identity and is deliberately a different axis from
|
|
28
|
+
* `CHAIN_PALETTE`: one says what you are looking at, the other says who is showing it to you.
|
|
29
|
+
*
|
|
30
|
+
* `name` matches the `consumerName` key each app already uses for its codex settings, so there is
|
|
31
|
+
* one spelling of "OuronetUI" across the workspace rather than two.
|
|
32
|
+
*/
|
|
33
|
+
export interface ConsumerIdentity {
|
|
34
|
+
name: string;
|
|
35
|
+
/** the app's own accent for the caller zone. NOT a chain colour. */
|
|
36
|
+
accent: string;
|
|
37
|
+
}
|
|
38
|
+
export declare const CONSUMERS: Readonly<Record<"OuronetUI" | "Codex", ConsumerIdentity>>;
|
|
1
39
|
/** One parameter of the execution, with everything a renderer needs about it. */
|
|
2
40
|
export interface TooltipSlot {
|
|
3
41
|
/** 1-based, so a renderer never has to decide whether to add one. */
|
|
@@ -13,6 +51,14 @@ export interface TooltipSlot {
|
|
|
13
51
|
isPreflightFed: boolean;
|
|
14
52
|
/** false = never prefill into an input that can reach a signed transaction (guards). */
|
|
15
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;
|
|
16
62
|
/** the registry's own note about this argument, when it has one. */
|
|
17
63
|
note?: string;
|
|
18
64
|
}
|
|
@@ -33,11 +79,8 @@ export interface TooltipModel {
|
|
|
33
79
|
* kadena Kadena mainnet's `coin`. A DIFFERENT CHAIN -- different gas, different accounts,
|
|
34
80
|
* and nothing about Ouronet applies to it.
|
|
35
81
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* and green for Kadena, and all are conformant. Mandating a palette in a package consumed by
|
|
39
|
-
* applications with their own design languages is a rule that gets ignored, and an ignored rule
|
|
40
|
-
* weakens the ones that matter.
|
|
82
|
+
* Each has a canonical colour in `CHAIN_PALETTE`, and a renderer should use it: the colour
|
|
83
|
+
* encodes which chain the user's money is on, which is shared vocabulary rather than styling.
|
|
41
84
|
*
|
|
42
85
|
* RENAMED from `"native"` in 2.0.0. With only two worlds "native" was unambiguous; with three
|
|
43
86
|
* it silently invited the question "native to WHAT" -- and both candidate answers are a
|
|
@@ -57,6 +100,12 @@ export interface TooltipModel {
|
|
|
57
100
|
* latency the user pays for a foregone conclusion. Rule 5.
|
|
58
101
|
*/
|
|
59
102
|
shouldRead: boolean;
|
|
103
|
+
/** the canonical border colour for `kind`. Convenience -- identical to CHAIN_PALETTE[kind]. */
|
|
104
|
+
chainColor: string;
|
|
105
|
+
/** the label to print beside it: OURONET / STOA NATIVE / KADENA. */
|
|
106
|
+
chainLabel: string;
|
|
107
|
+
/** who is rendering, for the caller zone. Undefined when the caller did not say. */
|
|
108
|
+
consumer?: ConsumerIdentity;
|
|
60
109
|
/** things a renderer may want to surface. Never thrown; a tooltip must not take a page down. */
|
|
61
110
|
warnings: string[];
|
|
62
111
|
}
|
|
@@ -110,7 +159,7 @@ export declare const isNativeKey: (key: string) => boolean;
|
|
|
110
159
|
* unresolvable argument becomes a visible placeholder rather than an exception, because a tooltip
|
|
111
160
|
* must never take down the page it annotates.
|
|
112
161
|
*/
|
|
113
|
-
export declare function tooltipModel(key: string, values?: Readonly<Record<string, string
|
|
162
|
+
export declare function tooltipModel(key: string, values?: Readonly<Record<string, string>>, consumer?: ConsumerIdentity): TooltipModel;
|
|
114
163
|
/**
|
|
115
164
|
* Models for a button that fronts a CHOICE of executions, in the order the ZBOM presents them.
|
|
116
165
|
*
|
|
@@ -119,7 +168,7 @@ export declare function tooltipModel(key: string, values?: Readonly<Record<strin
|
|
|
119
168
|
* caller instead -- and if nothing survives, the caller renders no tooltip, which is the correct
|
|
120
169
|
* outcome and not a crash.
|
|
121
170
|
*/
|
|
122
|
-
export declare function tooltipModels(keys: readonly string[], values?: Readonly<Record<string, string
|
|
171
|
+
export declare function tooltipModels(keys: readonly string[], values?: Readonly<Record<string, string>>, consumer?: ConsumerIdentity): TooltipModel[];
|
|
123
172
|
/**
|
|
124
173
|
* The type row -- rule 3.
|
|
125
174
|
*
|
|
@@ -130,3 +179,30 @@ export declare function signatureRows(m: TooltipModel): {
|
|
|
130
179
|
names: string[];
|
|
131
180
|
types: string[];
|
|
132
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
|
@@ -22,12 +22,22 @@
|
|
|
22
22
|
* 3. TYPES GO ON THEIR OWN ROW. `patron:string executor:string ...` doubles the width of the
|
|
23
23
|
* widest line in the panel. A parallel row under the names costs one line and reads better.
|
|
24
24
|
*
|
|
25
|
-
* 4. THREE WORLDS,
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* 4. THREE WORLDS, WITH A CANONICAL COLOUR EACH. `ouronet` (blue), `stoa` (gold), `kadena`
|
|
26
|
+
* (green). They differ in what they cost and what can be previewed. Only `ouronet` has an
|
|
27
|
+
* INFO_ reader and collects IGNIS; gas is sponsored on the Stoa side regardless -- claiming
|
|
28
|
+
* otherwise tells a user they are about to spend when they are not.
|
|
29
|
+
*
|
|
30
|
+
* THE PALETTE IS NOW CANON, reversing the 1.4.0 position that it was each app's business.
|
|
31
|
+
* The argument then was that a package should not dictate colours inside somebody else's
|
|
32
|
+
* design language, and that was right about DECORATION and wrong about this: the colour
|
|
33
|
+
* encodes WHICH CHAIN YOUR MONEY IS ON. A user who learns green-means-Kadena in one app and
|
|
34
|
+
* meets green-means-something-else in the other has been taught a falsehood by the
|
|
35
|
+
* inconsistency, and the two apps share users. A shared vocabulary has to be shared.
|
|
36
|
+
*
|
|
37
|
+
* 4b. SAY WHO IS RENDERING. Two applications draw this tooltip, and they draw it over different
|
|
38
|
+
* surfaces for the same chains. A caller zone naming the consumer costs one line and answers
|
|
39
|
+
* "which app am I looking at" without the user having to infer it from chrome -- which matters
|
|
40
|
+
* most in exactly the case where it is hardest, a Codex panel over an OuronetUI page.
|
|
31
41
|
*
|
|
32
42
|
* 0. CHAINWEB ONLY -- the rule that decides whether a tooltip exists at all. This model describes
|
|
33
43
|
* a PACT call on a Chainweb chain: what function, what arguments, what it costs. A button that
|
|
@@ -41,6 +51,37 @@
|
|
|
41
51
|
*/
|
|
42
52
|
import { getEntrypoint, getPreview, tryGetEntrypoint, registry } from "./registry.js";
|
|
43
53
|
import { formatForType } from "./format.js";
|
|
54
|
+
/**
|
|
55
|
+
* The canonical border colour per chain. USE THESE.
|
|
56
|
+
*
|
|
57
|
+
* Not styling: the colour tells a user which chain their money is on, and that vocabulary is
|
|
58
|
+
* shared between the applications that render it. Two apps teaching different meanings for the
|
|
59
|
+
* same colour is worse than neither using colour at all, because the user believes the first one
|
|
60
|
+
* they learned.
|
|
61
|
+
*
|
|
62
|
+
* ouronet blue the ouronet-ns surface -- priced, IGNIS, sponsored
|
|
63
|
+
* stoa gold StoaChain's own coin -- unpriced, no IGNIS, still sponsored
|
|
64
|
+
* kadena green a DIFFERENT CHAIN -- its own gas, its own balances
|
|
65
|
+
*
|
|
66
|
+
* Chosen from what was already in use rather than invented: gold is OuronetUI's STOA accent and
|
|
67
|
+
* blue its established `#3b82f6`; green is the app's existing success green, which is unused on
|
|
68
|
+
* any other tooltip surface and therefore free to carry this meaning.
|
|
69
|
+
*/
|
|
70
|
+
export const CHAIN_PALETTE = {
|
|
71
|
+
ouronet: "#3b82f6",
|
|
72
|
+
stoa: "#ceac5f",
|
|
73
|
+
kadena: "#22c55e",
|
|
74
|
+
};
|
|
75
|
+
/** Human label for the chain, for the border-adjacent marker. */
|
|
76
|
+
export const CHAIN_LABEL = {
|
|
77
|
+
ouronet: "OURONET",
|
|
78
|
+
stoa: "STOA NATIVE",
|
|
79
|
+
kadena: "KADENA",
|
|
80
|
+
};
|
|
81
|
+
export const CONSUMERS = {
|
|
82
|
+
OuronetUI: { name: "OuronetUI", accent: "#d2d3d4" },
|
|
83
|
+
Codex: { name: "Codex", accent: "#8b5cf6" },
|
|
84
|
+
};
|
|
44
85
|
/** The registry's generic placeholder: an entity id for something that does not exist on chain. */
|
|
45
86
|
export const PLACEHOLDER = '"example"';
|
|
46
87
|
export const isPlaceholder = (rendered) => rendered === PLACEHOLDER;
|
|
@@ -124,7 +165,7 @@ const KADENA_GHOST = {
|
|
|
124
165
|
bool: "false",
|
|
125
166
|
guard: '(read-keyset "ks")',
|
|
126
167
|
};
|
|
127
|
-
function offRegistryModel(key, kind, values) {
|
|
168
|
+
function offRegistryModel(key, kind, values, consumer) {
|
|
128
169
|
const sig = (kind === "stoa" ? STOA_SIGNATURES : KADENA_SIGNATURES)[key];
|
|
129
170
|
if (!sig)
|
|
130
171
|
throw new Error(`offRegistryModel: no signature for "${key}"`);
|
|
@@ -132,6 +173,9 @@ function offRegistryModel(key, kind, values) {
|
|
|
132
173
|
return {
|
|
133
174
|
kind,
|
|
134
175
|
exec: key,
|
|
176
|
+
chainColor: CHAIN_PALETTE[kind],
|
|
177
|
+
chainLabel: CHAIN_LABEL[kind],
|
|
178
|
+
consumer,
|
|
135
179
|
slots: sig.map(([name, type], i) => ({
|
|
136
180
|
index: i + 1,
|
|
137
181
|
name,
|
|
@@ -141,6 +185,7 @@ function offRegistryModel(key, kind, values) {
|
|
|
141
185
|
isPreflightFed: false,
|
|
142
186
|
// A guard is never prefillable, on any chain. Same rule, same reason.
|
|
143
187
|
prefillable: type !== "guard",
|
|
188
|
+
supplied: values[name] !== undefined,
|
|
144
189
|
})),
|
|
145
190
|
// No preview, deliberately. Neither chain's `coin` has a reader that prices a call, so there
|
|
146
191
|
// is no cost to show -- and a renderer must SAY that rather than leaving an empty panel,
|
|
@@ -160,10 +205,10 @@ function offRegistryModel(key, kind, values) {
|
|
|
160
205
|
* unresolvable argument becomes a visible placeholder rather than an exception, because a tooltip
|
|
161
206
|
* must never take down the page it annotates.
|
|
162
207
|
*/
|
|
163
|
-
export function tooltipModel(key, values = {}) {
|
|
208
|
+
export function tooltipModel(key, values = {}, consumer) {
|
|
164
209
|
const chain = chainOf(key);
|
|
165
210
|
if (chain === "stoa" || chain === "kadena")
|
|
166
|
-
return offRegistryModel(key, chain, values);
|
|
211
|
+
return offRegistryModel(key, chain, values, consumer);
|
|
167
212
|
if (chain === undefined && isOffRegistryKey(key))
|
|
168
213
|
throw new Error(`tooltipModel: "${key}" matched no chain. This is a bug in chainOf.`);
|
|
169
214
|
const ep = getEntrypoint(key); // throws, and names near matches, on a stale key
|
|
@@ -213,6 +258,7 @@ export function tooltipModel(key, values = {}) {
|
|
|
213
258
|
isPlaceholder,
|
|
214
259
|
isPreflightFed,
|
|
215
260
|
prefillable: u?.zbom !== false,
|
|
261
|
+
supplied: supplied !== undefined,
|
|
216
262
|
note: ep.ghost.notes?.[p.name],
|
|
217
263
|
};
|
|
218
264
|
});
|
|
@@ -249,6 +295,9 @@ export function tooltipModel(key, values = {}) {
|
|
|
249
295
|
return {
|
|
250
296
|
kind: "ouronet",
|
|
251
297
|
exec: `${registry.namespace}.${key}`,
|
|
298
|
+
chainColor: CHAIN_PALETTE.ouronet,
|
|
299
|
+
chainLabel: CHAIN_LABEL.ouronet,
|
|
300
|
+
consumer,
|
|
252
301
|
slots,
|
|
253
302
|
preview,
|
|
254
303
|
// RULE 5: do not fire a read whose answer is a foregone refusal.
|
|
@@ -264,10 +313,10 @@ export function tooltipModel(key, values = {}) {
|
|
|
264
313
|
* caller instead -- and if nothing survives, the caller renders no tooltip, which is the correct
|
|
265
314
|
* outcome and not a crash.
|
|
266
315
|
*/
|
|
267
|
-
export function tooltipModels(keys, values = {}) {
|
|
316
|
+
export function tooltipModels(keys, values = {}, consumer) {
|
|
268
317
|
return keys
|
|
269
318
|
.filter((k) => chainOf(k) !== undefined)
|
|
270
|
-
.map((k) => tooltipModel(k, values));
|
|
319
|
+
.map((k) => tooltipModel(k, values, consumer));
|
|
271
320
|
}
|
|
272
321
|
/**
|
|
273
322
|
* The type row -- rule 3.
|
|
@@ -278,3 +327,81 @@ export function tooltipModels(keys, values = {}) {
|
|
|
278
327
|
export function signatureRows(m) {
|
|
279
328
|
return { names: m.slots.map((s) => s.name), types: m.slots.map((s) => s.type) };
|
|
280
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