@calimero-network/mero-js 19.5.0 → 19.7.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.
@@ -0,0 +1,76 @@
1
+ /** An account root: the secret, the key it derives, and the account it names. */
2
+ export interface AccountRoot {
3
+ /**
4
+ * The root signing secret, 64 hex.
5
+ *
6
+ * The whole account. It signs device certificates and cloud links, and there
7
+ * is no recovery path that does not go through it or its phrase — so it is
8
+ * never sent anywhere, and in a browser it does not belong in `localStorage`.
9
+ */
10
+ secret: string;
11
+ /** The root's ed25519 public key, 64 hex. Safe to publish. */
12
+ publicKey: string;
13
+ /** The account this root names, 64 hex — the content address of its genesis. */
14
+ accountId: string;
15
+ }
16
+ /** An account root together with the phrase that restores it. */
17
+ export interface RecoverableAccountRoot extends AccountRoot {
18
+ /**
19
+ * A 24-word BIP39 English recovery phrase, single-space separated.
20
+ *
21
+ * Show it once, have the holder write it down, and do not keep it: it is the
22
+ * secret in a form a person can copy by hand without transcription errors.
23
+ */
24
+ phrase: string;
25
+ }
26
+ /**
27
+ * Mint a brand-new account root from the platform CSPRNG.
28
+ *
29
+ * This is the "generate a new key" half of cloud registration — the other half
30
+ * being a root the holder already has, on a desktop app or a hardware key, which
31
+ * signs without this ever running.
32
+ *
33
+ * **Interop note, and it matters.** The phrase encodes the root secret as BIP39
34
+ * *entropy*, not as a BIP39 *seed*. A tool restoring it must call the equivalent
35
+ * of `mnemonicToEntropy(phrase)` — 32 bytes — and use those bytes as the ed25519
36
+ * secret directly. `mnemonicToSeed(phrase)`, which most wallet libraries reach
37
+ * for first, runs PBKDF2 and returns 64 different bytes; feeding those in names
38
+ * a different account and fails as "wrong account", not as a decoding error.
39
+ * There is no passphrase and no BIP32 derivation path: the 24 words are the key.
40
+ */
41
+ export declare function generateAccountRoot(): Promise<RecoverableAccountRoot>;
42
+ /**
43
+ * Restore an account root from its recovery phrase.
44
+ *
45
+ * Whitespace and case are normalised, so a phrase pasted out of a text editor
46
+ * with a trailing newline or a stray double space restores fine. A word outside
47
+ * the list, a wrong word count, or a failed checksum throws rather than
48
+ * returning some other account — a single mistyped word is the common case, and
49
+ * BIP39's checksum catches all but 1 in 256 of them.
50
+ */
51
+ export declare function accountRootFromPhrase(phrase: string): Promise<RecoverableAccountRoot>;
52
+ /** The public half of a root you already hold, without re-deriving it by hand. */
53
+ export declare function accountRootFromSecret(secret: string): Promise<AccountRoot>;
54
+ /** What {@link signAccountLink} needs. */
55
+ export interface AccountLinkInput {
56
+ /** The account root's signing secret, 64 hex. */
57
+ rootSecret: string;
58
+ /**
59
+ * The challenge from `GET /api/cloud/me/accounts/challenge`, verbatim.
60
+ *
61
+ * Signed as its UTF-8 bytes, not decoded first: mdma seals it as an opaque
62
+ * string and verifies over the same string it issued.
63
+ */
64
+ nonce: string;
65
+ }
66
+ /**
67
+ * Sign a cloud link challenge with the account root. Returns base64.
68
+ *
69
+ * Standard base64, not base64url — mdma decodes it with `validate=True`, so the
70
+ * `-`/`_` alphabet is rejected outright rather than silently mis-decoded.
71
+ *
72
+ * Root-signed rather than device-signed on purpose: this is the credential
73
+ * someone still holds after losing a device, which is the case linking exists to
74
+ * serve.
75
+ */
76
+ export declare function signAccountLink(input: AccountLinkInput): Promise<string>;
Binary file
@@ -0,0 +1,2 @@
1
+ export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, signAccountLink, } from './account.js';
2
+ export type { AccountRoot, RecoverableAccountRoot, AccountLinkInput, } from './account.js';
@@ -0,0 +1,2 @@
1
+ // Account roots — minting one, restoring it from a phrase, and proving you hold it.
2
+ export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, signAccountLink, } from './account.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The BIP39 English wordlist, verbatim — 2048 words, index order significant.
3
+ *
4
+ * Vendored rather than depended on because this package ships with no runtime
5
+ * dependencies, and a recovery phrase is useless if the list it was written
6
+ * against is not the one everybody else implements. The list is content-checked
7
+ * in `account.test.ts` against its canonical SHA-256
8
+ * (`2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda` over the
9
+ * newline-joined, newline-terminated file), so a stray edit here fails the suite
10
+ * instead of silently minting phrases no other wallet can restore.
11
+ *
12
+ * Its own module so bundlers can drop it: nothing outside `account/` imports it,
13
+ * and the package is `sideEffects: false`, so a consumer who only signs never
14
+ * pays for the ~13 KB.
15
+ */
16
+ export declare const ENGLISH_WORDLIST: readonly string[];
@@ -0,0 +1,273 @@
1
+ /**
2
+ * The BIP39 English wordlist, verbatim — 2048 words, index order significant.
3
+ *
4
+ * Vendored rather than depended on because this package ships with no runtime
5
+ * dependencies, and a recovery phrase is useless if the list it was written
6
+ * against is not the one everybody else implements. The list is content-checked
7
+ * in `account.test.ts` against its canonical SHA-256
8
+ * (`2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda` over the
9
+ * newline-joined, newline-terminated file), so a stray edit here fails the suite
10
+ * instead of silently minting phrases no other wallet can restore.
11
+ *
12
+ * Its own module so bundlers can drop it: nothing outside `account/` imports it,
13
+ * and the package is `sideEffects: false`, so a consumer who only signs never
14
+ * pays for the ~13 KB.
15
+ */
16
+ export const ENGLISH_WORDLIST = [
17
+ 'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract',
18
+ 'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid',
19
+ 'acoustic', 'acquire', 'across', 'act', 'action', 'actor', 'actress', 'actual',
20
+ 'adapt', 'add', 'addict', 'address', 'adjust', 'admit', 'adult', 'advance',
21
+ 'advice', 'aerobic', 'affair', 'afford', 'afraid', 'again', 'age', 'agent',
22
+ 'agree', 'ahead', 'aim', 'air', 'airport', 'aisle', 'alarm', 'album',
23
+ 'alcohol', 'alert', 'alien', 'all', 'alley', 'allow', 'almost', 'alone',
24
+ 'alpha', 'already', 'also', 'alter', 'always', 'amateur', 'amazing', 'among',
25
+ 'amount', 'amused', 'analyst', 'anchor', 'ancient', 'anger', 'angle', 'angry',
26
+ 'animal', 'ankle', 'announce', 'annual', 'another', 'answer', 'antenna', 'antique',
27
+ 'anxiety', 'any', 'apart', 'apology', 'appear', 'apple', 'approve', 'april',
28
+ 'arch', 'arctic', 'area', 'arena', 'argue', 'arm', 'armed', 'armor',
29
+ 'army', 'around', 'arrange', 'arrest', 'arrive', 'arrow', 'art', 'artefact',
30
+ 'artist', 'artwork', 'ask', 'aspect', 'assault', 'asset', 'assist', 'assume',
31
+ 'asthma', 'athlete', 'atom', 'attack', 'attend', 'attitude', 'attract', 'auction',
32
+ 'audit', 'august', 'aunt', 'author', 'auto', 'autumn', 'average', 'avocado',
33
+ 'avoid', 'awake', 'aware', 'away', 'awesome', 'awful', 'awkward', 'axis',
34
+ 'baby', 'bachelor', 'bacon', 'badge', 'bag', 'balance', 'balcony', 'ball',
35
+ 'bamboo', 'banana', 'banner', 'bar', 'barely', 'bargain', 'barrel', 'base',
36
+ 'basic', 'basket', 'battle', 'beach', 'bean', 'beauty', 'because', 'become',
37
+ 'beef', 'before', 'begin', 'behave', 'behind', 'believe', 'below', 'belt',
38
+ 'bench', 'benefit', 'best', 'betray', 'better', 'between', 'beyond', 'bicycle',
39
+ 'bid', 'bike', 'bind', 'biology', 'bird', 'birth', 'bitter', 'black',
40
+ 'blade', 'blame', 'blanket', 'blast', 'bleak', 'bless', 'blind', 'blood',
41
+ 'blossom', 'blouse', 'blue', 'blur', 'blush', 'board', 'boat', 'body',
42
+ 'boil', 'bomb', 'bone', 'bonus', 'book', 'boost', 'border', 'boring',
43
+ 'borrow', 'boss', 'bottom', 'bounce', 'box', 'boy', 'bracket', 'brain',
44
+ 'brand', 'brass', 'brave', 'bread', 'breeze', 'brick', 'bridge', 'brief',
45
+ 'bright', 'bring', 'brisk', 'broccoli', 'broken', 'bronze', 'broom', 'brother',
46
+ 'brown', 'brush', 'bubble', 'buddy', 'budget', 'buffalo', 'build', 'bulb',
47
+ 'bulk', 'bullet', 'bundle', 'bunker', 'burden', 'burger', 'burst', 'bus',
48
+ 'business', 'busy', 'butter', 'buyer', 'buzz', 'cabbage', 'cabin', 'cable',
49
+ 'cactus', 'cage', 'cake', 'call', 'calm', 'camera', 'camp', 'can',
50
+ 'canal', 'cancel', 'candy', 'cannon', 'canoe', 'canvas', 'canyon', 'capable',
51
+ 'capital', 'captain', 'car', 'carbon', 'card', 'cargo', 'carpet', 'carry',
52
+ 'cart', 'case', 'cash', 'casino', 'castle', 'casual', 'cat', 'catalog',
53
+ 'catch', 'category', 'cattle', 'caught', 'cause', 'caution', 'cave', 'ceiling',
54
+ 'celery', 'cement', 'census', 'century', 'cereal', 'certain', 'chair', 'chalk',
55
+ 'champion', 'change', 'chaos', 'chapter', 'charge', 'chase', 'chat', 'cheap',
56
+ 'check', 'cheese', 'chef', 'cherry', 'chest', 'chicken', 'chief', 'child',
57
+ 'chimney', 'choice', 'choose', 'chronic', 'chuckle', 'chunk', 'churn', 'cigar',
58
+ 'cinnamon', 'circle', 'citizen', 'city', 'civil', 'claim', 'clap', 'clarify',
59
+ 'claw', 'clay', 'clean', 'clerk', 'clever', 'click', 'client', 'cliff',
60
+ 'climb', 'clinic', 'clip', 'clock', 'clog', 'close', 'cloth', 'cloud',
61
+ 'clown', 'club', 'clump', 'cluster', 'clutch', 'coach', 'coast', 'coconut',
62
+ 'code', 'coffee', 'coil', 'coin', 'collect', 'color', 'column', 'combine',
63
+ 'come', 'comfort', 'comic', 'common', 'company', 'concert', 'conduct', 'confirm',
64
+ 'congress', 'connect', 'consider', 'control', 'convince', 'cook', 'cool', 'copper',
65
+ 'copy', 'coral', 'core', 'corn', 'correct', 'cost', 'cotton', 'couch',
66
+ 'country', 'couple', 'course', 'cousin', 'cover', 'coyote', 'crack', 'cradle',
67
+ 'craft', 'cram', 'crane', 'crash', 'crater', 'crawl', 'crazy', 'cream',
68
+ 'credit', 'creek', 'crew', 'cricket', 'crime', 'crisp', 'critic', 'crop',
69
+ 'cross', 'crouch', 'crowd', 'crucial', 'cruel', 'cruise', 'crumble', 'crunch',
70
+ 'crush', 'cry', 'crystal', 'cube', 'culture', 'cup', 'cupboard', 'curious',
71
+ 'current', 'curtain', 'curve', 'cushion', 'custom', 'cute', 'cycle', 'dad',
72
+ 'damage', 'damp', 'dance', 'danger', 'daring', 'dash', 'daughter', 'dawn',
73
+ 'day', 'deal', 'debate', 'debris', 'decade', 'december', 'decide', 'decline',
74
+ 'decorate', 'decrease', 'deer', 'defense', 'define', 'defy', 'degree', 'delay',
75
+ 'deliver', 'demand', 'demise', 'denial', 'dentist', 'deny', 'depart', 'depend',
76
+ 'deposit', 'depth', 'deputy', 'derive', 'describe', 'desert', 'design', 'desk',
77
+ 'despair', 'destroy', 'detail', 'detect', 'develop', 'device', 'devote', 'diagram',
78
+ 'dial', 'diamond', 'diary', 'dice', 'diesel', 'diet', 'differ', 'digital',
79
+ 'dignity', 'dilemma', 'dinner', 'dinosaur', 'direct', 'dirt', 'disagree', 'discover',
80
+ 'disease', 'dish', 'dismiss', 'disorder', 'display', 'distance', 'divert', 'divide',
81
+ 'divorce', 'dizzy', 'doctor', 'document', 'dog', 'doll', 'dolphin', 'domain',
82
+ 'donate', 'donkey', 'donor', 'door', 'dose', 'double', 'dove', 'draft',
83
+ 'dragon', 'drama', 'drastic', 'draw', 'dream', 'dress', 'drift', 'drill',
84
+ 'drink', 'drip', 'drive', 'drop', 'drum', 'dry', 'duck', 'dumb',
85
+ 'dune', 'during', 'dust', 'dutch', 'duty', 'dwarf', 'dynamic', 'eager',
86
+ 'eagle', 'early', 'earn', 'earth', 'easily', 'east', 'easy', 'echo',
87
+ 'ecology', 'economy', 'edge', 'edit', 'educate', 'effort', 'egg', 'eight',
88
+ 'either', 'elbow', 'elder', 'electric', 'elegant', 'element', 'elephant', 'elevator',
89
+ 'elite', 'else', 'embark', 'embody', 'embrace', 'emerge', 'emotion', 'employ',
90
+ 'empower', 'empty', 'enable', 'enact', 'end', 'endless', 'endorse', 'enemy',
91
+ 'energy', 'enforce', 'engage', 'engine', 'enhance', 'enjoy', 'enlist', 'enough',
92
+ 'enrich', 'enroll', 'ensure', 'enter', 'entire', 'entry', 'envelope', 'episode',
93
+ 'equal', 'equip', 'era', 'erase', 'erode', 'erosion', 'error', 'erupt',
94
+ 'escape', 'essay', 'essence', 'estate', 'eternal', 'ethics', 'evidence', 'evil',
95
+ 'evoke', 'evolve', 'exact', 'example', 'excess', 'exchange', 'excite', 'exclude',
96
+ 'excuse', 'execute', 'exercise', 'exhaust', 'exhibit', 'exile', 'exist', 'exit',
97
+ 'exotic', 'expand', 'expect', 'expire', 'explain', 'expose', 'express', 'extend',
98
+ 'extra', 'eye', 'eyebrow', 'fabric', 'face', 'faculty', 'fade', 'faint',
99
+ 'faith', 'fall', 'false', 'fame', 'family', 'famous', 'fan', 'fancy',
100
+ 'fantasy', 'farm', 'fashion', 'fat', 'fatal', 'father', 'fatigue', 'fault',
101
+ 'favorite', 'feature', 'february', 'federal', 'fee', 'feed', 'feel', 'female',
102
+ 'fence', 'festival', 'fetch', 'fever', 'few', 'fiber', 'fiction', 'field',
103
+ 'figure', 'file', 'film', 'filter', 'final', 'find', 'fine', 'finger',
104
+ 'finish', 'fire', 'firm', 'first', 'fiscal', 'fish', 'fit', 'fitness',
105
+ 'fix', 'flag', 'flame', 'flash', 'flat', 'flavor', 'flee', 'flight',
106
+ 'flip', 'float', 'flock', 'floor', 'flower', 'fluid', 'flush', 'fly',
107
+ 'foam', 'focus', 'fog', 'foil', 'fold', 'follow', 'food', 'foot',
108
+ 'force', 'forest', 'forget', 'fork', 'fortune', 'forum', 'forward', 'fossil',
109
+ 'foster', 'found', 'fox', 'fragile', 'frame', 'frequent', 'fresh', 'friend',
110
+ 'fringe', 'frog', 'front', 'frost', 'frown', 'frozen', 'fruit', 'fuel',
111
+ 'fun', 'funny', 'furnace', 'fury', 'future', 'gadget', 'gain', 'galaxy',
112
+ 'gallery', 'game', 'gap', 'garage', 'garbage', 'garden', 'garlic', 'garment',
113
+ 'gas', 'gasp', 'gate', 'gather', 'gauge', 'gaze', 'general', 'genius',
114
+ 'genre', 'gentle', 'genuine', 'gesture', 'ghost', 'giant', 'gift', 'giggle',
115
+ 'ginger', 'giraffe', 'girl', 'give', 'glad', 'glance', 'glare', 'glass',
116
+ 'glide', 'glimpse', 'globe', 'gloom', 'glory', 'glove', 'glow', 'glue',
117
+ 'goat', 'goddess', 'gold', 'good', 'goose', 'gorilla', 'gospel', 'gossip',
118
+ 'govern', 'gown', 'grab', 'grace', 'grain', 'grant', 'grape', 'grass',
119
+ 'gravity', 'great', 'green', 'grid', 'grief', 'grit', 'grocery', 'group',
120
+ 'grow', 'grunt', 'guard', 'guess', 'guide', 'guilt', 'guitar', 'gun',
121
+ 'gym', 'habit', 'hair', 'half', 'hammer', 'hamster', 'hand', 'happy',
122
+ 'harbor', 'hard', 'harsh', 'harvest', 'hat', 'have', 'hawk', 'hazard',
123
+ 'head', 'health', 'heart', 'heavy', 'hedgehog', 'height', 'hello', 'helmet',
124
+ 'help', 'hen', 'hero', 'hidden', 'high', 'hill', 'hint', 'hip',
125
+ 'hire', 'history', 'hobby', 'hockey', 'hold', 'hole', 'holiday', 'hollow',
126
+ 'home', 'honey', 'hood', 'hope', 'horn', 'horror', 'horse', 'hospital',
127
+ 'host', 'hotel', 'hour', 'hover', 'hub', 'huge', 'human', 'humble',
128
+ 'humor', 'hundred', 'hungry', 'hunt', 'hurdle', 'hurry', 'hurt', 'husband',
129
+ 'hybrid', 'ice', 'icon', 'idea', 'identify', 'idle', 'ignore', 'ill',
130
+ 'illegal', 'illness', 'image', 'imitate', 'immense', 'immune', 'impact', 'impose',
131
+ 'improve', 'impulse', 'inch', 'include', 'income', 'increase', 'index', 'indicate',
132
+ 'indoor', 'industry', 'infant', 'inflict', 'inform', 'inhale', 'inherit', 'initial',
133
+ 'inject', 'injury', 'inmate', 'inner', 'innocent', 'input', 'inquiry', 'insane',
134
+ 'insect', 'inside', 'inspire', 'install', 'intact', 'interest', 'into', 'invest',
135
+ 'invite', 'involve', 'iron', 'island', 'isolate', 'issue', 'item', 'ivory',
136
+ 'jacket', 'jaguar', 'jar', 'jazz', 'jealous', 'jeans', 'jelly', 'jewel',
137
+ 'job', 'join', 'joke', 'journey', 'joy', 'judge', 'juice', 'jump',
138
+ 'jungle', 'junior', 'junk', 'just', 'kangaroo', 'keen', 'keep', 'ketchup',
139
+ 'key', 'kick', 'kid', 'kidney', 'kind', 'kingdom', 'kiss', 'kit',
140
+ 'kitchen', 'kite', 'kitten', 'kiwi', 'knee', 'knife', 'knock', 'know',
141
+ 'lab', 'label', 'labor', 'ladder', 'lady', 'lake', 'lamp', 'language',
142
+ 'laptop', 'large', 'later', 'latin', 'laugh', 'laundry', 'lava', 'law',
143
+ 'lawn', 'lawsuit', 'layer', 'lazy', 'leader', 'leaf', 'learn', 'leave',
144
+ 'lecture', 'left', 'leg', 'legal', 'legend', 'leisure', 'lemon', 'lend',
145
+ 'length', 'lens', 'leopard', 'lesson', 'letter', 'level', 'liar', 'liberty',
146
+ 'library', 'license', 'life', 'lift', 'light', 'like', 'limb', 'limit',
147
+ 'link', 'lion', 'liquid', 'list', 'little', 'live', 'lizard', 'load',
148
+ 'loan', 'lobster', 'local', 'lock', 'logic', 'lonely', 'long', 'loop',
149
+ 'lottery', 'loud', 'lounge', 'love', 'loyal', 'lucky', 'luggage', 'lumber',
150
+ 'lunar', 'lunch', 'luxury', 'lyrics', 'machine', 'mad', 'magic', 'magnet',
151
+ 'maid', 'mail', 'main', 'major', 'make', 'mammal', 'man', 'manage',
152
+ 'mandate', 'mango', 'mansion', 'manual', 'maple', 'marble', 'march', 'margin',
153
+ 'marine', 'market', 'marriage', 'mask', 'mass', 'master', 'match', 'material',
154
+ 'math', 'matrix', 'matter', 'maximum', 'maze', 'meadow', 'mean', 'measure',
155
+ 'meat', 'mechanic', 'medal', 'media', 'melody', 'melt', 'member', 'memory',
156
+ 'mention', 'menu', 'mercy', 'merge', 'merit', 'merry', 'mesh', 'message',
157
+ 'metal', 'method', 'middle', 'midnight', 'milk', 'million', 'mimic', 'mind',
158
+ 'minimum', 'minor', 'minute', 'miracle', 'mirror', 'misery', 'miss', 'mistake',
159
+ 'mix', 'mixed', 'mixture', 'mobile', 'model', 'modify', 'mom', 'moment',
160
+ 'monitor', 'monkey', 'monster', 'month', 'moon', 'moral', 'more', 'morning',
161
+ 'mosquito', 'mother', 'motion', 'motor', 'mountain', 'mouse', 'move', 'movie',
162
+ 'much', 'muffin', 'mule', 'multiply', 'muscle', 'museum', 'mushroom', 'music',
163
+ 'must', 'mutual', 'myself', 'mystery', 'myth', 'naive', 'name', 'napkin',
164
+ 'narrow', 'nasty', 'nation', 'nature', 'near', 'neck', 'need', 'negative',
165
+ 'neglect', 'neither', 'nephew', 'nerve', 'nest', 'net', 'network', 'neutral',
166
+ 'never', 'news', 'next', 'nice', 'night', 'noble', 'noise', 'nominee',
167
+ 'noodle', 'normal', 'north', 'nose', 'notable', 'note', 'nothing', 'notice',
168
+ 'novel', 'now', 'nuclear', 'number', 'nurse', 'nut', 'oak', 'obey',
169
+ 'object', 'oblige', 'obscure', 'observe', 'obtain', 'obvious', 'occur', 'ocean',
170
+ 'october', 'odor', 'off', 'offer', 'office', 'often', 'oil', 'okay',
171
+ 'old', 'olive', 'olympic', 'omit', 'once', 'one', 'onion', 'online',
172
+ 'only', 'open', 'opera', 'opinion', 'oppose', 'option', 'orange', 'orbit',
173
+ 'orchard', 'order', 'ordinary', 'organ', 'orient', 'original', 'orphan', 'ostrich',
174
+ 'other', 'outdoor', 'outer', 'output', 'outside', 'oval', 'oven', 'over',
175
+ 'own', 'owner', 'oxygen', 'oyster', 'ozone', 'pact', 'paddle', 'page',
176
+ 'pair', 'palace', 'palm', 'panda', 'panel', 'panic', 'panther', 'paper',
177
+ 'parade', 'parent', 'park', 'parrot', 'party', 'pass', 'patch', 'path',
178
+ 'patient', 'patrol', 'pattern', 'pause', 'pave', 'payment', 'peace', 'peanut',
179
+ 'pear', 'peasant', 'pelican', 'pen', 'penalty', 'pencil', 'people', 'pepper',
180
+ 'perfect', 'permit', 'person', 'pet', 'phone', 'photo', 'phrase', 'physical',
181
+ 'piano', 'picnic', 'picture', 'piece', 'pig', 'pigeon', 'pill', 'pilot',
182
+ 'pink', 'pioneer', 'pipe', 'pistol', 'pitch', 'pizza', 'place', 'planet',
183
+ 'plastic', 'plate', 'play', 'please', 'pledge', 'pluck', 'plug', 'plunge',
184
+ 'poem', 'poet', 'point', 'polar', 'pole', 'police', 'pond', 'pony',
185
+ 'pool', 'popular', 'portion', 'position', 'possible', 'post', 'potato', 'pottery',
186
+ 'poverty', 'powder', 'power', 'practice', 'praise', 'predict', 'prefer', 'prepare',
187
+ 'present', 'pretty', 'prevent', 'price', 'pride', 'primary', 'print', 'priority',
188
+ 'prison', 'private', 'prize', 'problem', 'process', 'produce', 'profit', 'program',
189
+ 'project', 'promote', 'proof', 'property', 'prosper', 'protect', 'proud', 'provide',
190
+ 'public', 'pudding', 'pull', 'pulp', 'pulse', 'pumpkin', 'punch', 'pupil',
191
+ 'puppy', 'purchase', 'purity', 'purpose', 'purse', 'push', 'put', 'puzzle',
192
+ 'pyramid', 'quality', 'quantum', 'quarter', 'question', 'quick', 'quit', 'quiz',
193
+ 'quote', 'rabbit', 'raccoon', 'race', 'rack', 'radar', 'radio', 'rail',
194
+ 'rain', 'raise', 'rally', 'ramp', 'ranch', 'random', 'range', 'rapid',
195
+ 'rare', 'rate', 'rather', 'raven', 'raw', 'razor', 'ready', 'real',
196
+ 'reason', 'rebel', 'rebuild', 'recall', 'receive', 'recipe', 'record', 'recycle',
197
+ 'reduce', 'reflect', 'reform', 'refuse', 'region', 'regret', 'regular', 'reject',
198
+ 'relax', 'release', 'relief', 'rely', 'remain', 'remember', 'remind', 'remove',
199
+ 'render', 'renew', 'rent', 'reopen', 'repair', 'repeat', 'replace', 'report',
200
+ 'require', 'rescue', 'resemble', 'resist', 'resource', 'response', 'result', 'retire',
201
+ 'retreat', 'return', 'reunion', 'reveal', 'review', 'reward', 'rhythm', 'rib',
202
+ 'ribbon', 'rice', 'rich', 'ride', 'ridge', 'rifle', 'right', 'rigid',
203
+ 'ring', 'riot', 'ripple', 'risk', 'ritual', 'rival', 'river', 'road',
204
+ 'roast', 'robot', 'robust', 'rocket', 'romance', 'roof', 'rookie', 'room',
205
+ 'rose', 'rotate', 'rough', 'round', 'route', 'royal', 'rubber', 'rude',
206
+ 'rug', 'rule', 'run', 'runway', 'rural', 'sad', 'saddle', 'sadness',
207
+ 'safe', 'sail', 'salad', 'salmon', 'salon', 'salt', 'salute', 'same',
208
+ 'sample', 'sand', 'satisfy', 'satoshi', 'sauce', 'sausage', 'save', 'say',
209
+ 'scale', 'scan', 'scare', 'scatter', 'scene', 'scheme', 'school', 'science',
210
+ 'scissors', 'scorpion', 'scout', 'scrap', 'screen', 'script', 'scrub', 'sea',
211
+ 'search', 'season', 'seat', 'second', 'secret', 'section', 'security', 'seed',
212
+ 'seek', 'segment', 'select', 'sell', 'seminar', 'senior', 'sense', 'sentence',
213
+ 'series', 'service', 'session', 'settle', 'setup', 'seven', 'shadow', 'shaft',
214
+ 'shallow', 'share', 'shed', 'shell', 'sheriff', 'shield', 'shift', 'shine',
215
+ 'ship', 'shiver', 'shock', 'shoe', 'shoot', 'shop', 'short', 'shoulder',
216
+ 'shove', 'shrimp', 'shrug', 'shuffle', 'shy', 'sibling', 'sick', 'side',
217
+ 'siege', 'sight', 'sign', 'silent', 'silk', 'silly', 'silver', 'similar',
218
+ 'simple', 'since', 'sing', 'siren', 'sister', 'situate', 'six', 'size',
219
+ 'skate', 'sketch', 'ski', 'skill', 'skin', 'skirt', 'skull', 'slab',
220
+ 'slam', 'sleep', 'slender', 'slice', 'slide', 'slight', 'slim', 'slogan',
221
+ 'slot', 'slow', 'slush', 'small', 'smart', 'smile', 'smoke', 'smooth',
222
+ 'snack', 'snake', 'snap', 'sniff', 'snow', 'soap', 'soccer', 'social',
223
+ 'sock', 'soda', 'soft', 'solar', 'soldier', 'solid', 'solution', 'solve',
224
+ 'someone', 'song', 'soon', 'sorry', 'sort', 'soul', 'sound', 'soup',
225
+ 'source', 'south', 'space', 'spare', 'spatial', 'spawn', 'speak', 'special',
226
+ 'speed', 'spell', 'spend', 'sphere', 'spice', 'spider', 'spike', 'spin',
227
+ 'spirit', 'split', 'spoil', 'sponsor', 'spoon', 'sport', 'spot', 'spray',
228
+ 'spread', 'spring', 'spy', 'square', 'squeeze', 'squirrel', 'stable', 'stadium',
229
+ 'staff', 'stage', 'stairs', 'stamp', 'stand', 'start', 'state', 'stay',
230
+ 'steak', 'steel', 'stem', 'step', 'stereo', 'stick', 'still', 'sting',
231
+ 'stock', 'stomach', 'stone', 'stool', 'story', 'stove', 'strategy', 'street',
232
+ 'strike', 'strong', 'struggle', 'student', 'stuff', 'stumble', 'style', 'subject',
233
+ 'submit', 'subway', 'success', 'such', 'sudden', 'suffer', 'sugar', 'suggest',
234
+ 'suit', 'summer', 'sun', 'sunny', 'sunset', 'super', 'supply', 'supreme',
235
+ 'sure', 'surface', 'surge', 'surprise', 'surround', 'survey', 'suspect', 'sustain',
236
+ 'swallow', 'swamp', 'swap', 'swarm', 'swear', 'sweet', 'swift', 'swim',
237
+ 'swing', 'switch', 'sword', 'symbol', 'symptom', 'syrup', 'system', 'table',
238
+ 'tackle', 'tag', 'tail', 'talent', 'talk', 'tank', 'tape', 'target',
239
+ 'task', 'taste', 'tattoo', 'taxi', 'teach', 'team', 'tell', 'ten',
240
+ 'tenant', 'tennis', 'tent', 'term', 'test', 'text', 'thank', 'that',
241
+ 'theme', 'then', 'theory', 'there', 'they', 'thing', 'this', 'thought',
242
+ 'three', 'thrive', 'throw', 'thumb', 'thunder', 'ticket', 'tide', 'tiger',
243
+ 'tilt', 'timber', 'time', 'tiny', 'tip', 'tired', 'tissue', 'title',
244
+ 'toast', 'tobacco', 'today', 'toddler', 'toe', 'together', 'toilet', 'token',
245
+ 'tomato', 'tomorrow', 'tone', 'tongue', 'tonight', 'tool', 'tooth', 'top',
246
+ 'topic', 'topple', 'torch', 'tornado', 'tortoise', 'toss', 'total', 'tourist',
247
+ 'toward', 'tower', 'town', 'toy', 'track', 'trade', 'traffic', 'tragic',
248
+ 'train', 'transfer', 'trap', 'trash', 'travel', 'tray', 'treat', 'tree',
249
+ 'trend', 'trial', 'tribe', 'trick', 'trigger', 'trim', 'trip', 'trophy',
250
+ 'trouble', 'truck', 'true', 'truly', 'trumpet', 'trust', 'truth', 'try',
251
+ 'tube', 'tuition', 'tumble', 'tuna', 'tunnel', 'turkey', 'turn', 'turtle',
252
+ 'twelve', 'twenty', 'twice', 'twin', 'twist', 'two', 'type', 'typical',
253
+ 'ugly', 'umbrella', 'unable', 'unaware', 'uncle', 'uncover', 'under', 'undo',
254
+ 'unfair', 'unfold', 'unhappy', 'uniform', 'unique', 'unit', 'universe', 'unknown',
255
+ 'unlock', 'until', 'unusual', 'unveil', 'update', 'upgrade', 'uphold', 'upon',
256
+ 'upper', 'upset', 'urban', 'urge', 'usage', 'use', 'used', 'useful',
257
+ 'useless', 'usual', 'utility', 'vacant', 'vacuum', 'vague', 'valid', 'valley',
258
+ 'valve', 'van', 'vanish', 'vapor', 'various', 'vast', 'vault', 'vehicle',
259
+ 'velvet', 'vendor', 'venture', 'venue', 'verb', 'verify', 'version', 'very',
260
+ 'vessel', 'veteran', 'viable', 'vibrant', 'vicious', 'victory', 'video', 'view',
261
+ 'village', 'vintage', 'violin', 'virtual', 'virus', 'visa', 'visit', 'visual',
262
+ 'vital', 'vivid', 'vocal', 'voice', 'void', 'volcano', 'volume', 'vote',
263
+ 'voyage', 'wage', 'wagon', 'wait', 'walk', 'wall', 'walnut', 'want',
264
+ 'warfare', 'warm', 'warrior', 'wash', 'wasp', 'waste', 'water', 'wave',
265
+ 'way', 'wealth', 'weapon', 'wear', 'weasel', 'weather', 'web', 'wedding',
266
+ 'weekend', 'weird', 'welcome', 'west', 'wet', 'whale', 'what', 'wheat',
267
+ 'wheel', 'when', 'where', 'whip', 'whisper', 'wide', 'width', 'wife',
268
+ 'wild', 'will', 'win', 'window', 'wine', 'wing', 'wink', 'winner',
269
+ 'winter', 'wire', 'wisdom', 'wise', 'wish', 'witness', 'wolf', 'woman',
270
+ 'wonder', 'wood', 'wool', 'word', 'work', 'world', 'worry', 'worth',
271
+ 'wrap', 'wreck', 'wrestle', 'wrist', 'write', 'wrong', 'yard', 'year',
272
+ 'yellow', 'you', 'young', 'youth', 'zebra', 'zero', 'zone', 'zoo',
273
+ ];
@@ -343,6 +343,75 @@ export declare class AdminApiClient {
343
343
  */
344
344
  setMemberCapabilities(groupId: string, identity: string, request: SetMemberCapabilitiesRequest): Promise<void>;
345
345
  setDefaultCapabilities(groupId: string, request: SetDefaultCapabilitiesRequest): Promise<void>;
346
+ /**
347
+ * Make every member admitted to `groupId` from now on able to relay a
348
+ * delegated write, without a per-node governance op each time.
349
+ *
350
+ * `CAN_AUTHOR_ON_BEHALF` is implied by nothing — not membership, not admin —
351
+ * so every group is authorship-closed and each fleet relay otherwise needs an
352
+ * admin to grant it individually, at the moment the relay is assigned and the
353
+ * admin is not watching. Setting it in the group's DEFAULT mask is core's own
354
+ * answer to that: `add_member` seeds a non-admin's capability row from the
355
+ * default, so an attested node admitted afterwards lands open.
356
+ *
357
+ * Call it on the NAMESPACE (the root group). A grant resolves through the
358
+ * membership anchor, so one at the root reaches every Open subgroup beneath
359
+ * it, which is where contexts actually live; a `Restricted` subgroup is a
360
+ * membership boundary and needs its own call.
361
+ *
362
+ * ### Two things this does not do
363
+ *
364
+ * **It is not retroactive.** The default is copied into a member's row when
365
+ * that member is admitted, so nodes already admitted keep the row they got.
366
+ * Use {@link grantAuthorship} for those — or call this at namespace creation,
367
+ * which is the only point that needs no backfill at all.
368
+ *
369
+ * **It does not reach admins.** Core seeds the default only for non-admin
370
+ * roles, and `CAN_AUTHOR_ON_BEHALF` is deliberately not implied by admin. An
371
+ * admin's own node therefore stays closed and needs {@link grantAuthorship}.
372
+ *
373
+ * ### What it widens
374
+ *
375
+ * Every future non-admin member of the group, not only attested TEE nodes, so
376
+ * any of them may be named as a warrant's `executor`. The bound worth knowing
377
+ * before deciding: an executor cannot FORGE. A delegated write is authorized
378
+ * by the author's own warrant — signed by their device key, committed to one
379
+ * context, method and exact arguments, with its nonce checked unspent — so a
380
+ * holder can only spend a warrant it was deliberately handed. What it does
381
+ * gain is the arguments in cleartext and the choice of when, or whether, to
382
+ * publish.
383
+ *
384
+ * Read-modify-write rather than a blind set: core seeds a new group's default
385
+ * with `CAN_JOIN_OPEN_SUBGROUPS`, and overwriting that would quietly stop
386
+ * every later member inheriting into Open subgroups.
387
+ *
388
+ * Returns the resulting mask and whether an op was published — it is a no-op
389
+ * when the bit is already set, so it is safe to call on every startup.
390
+ */
391
+ openToDelegatedExecution(groupId: string): Promise<{
392
+ changed: boolean;
393
+ defaultCapabilities: number;
394
+ }>;
395
+ /**
396
+ * Grant `account` the authorship bit on `groupId`, leaving its other
397
+ * capabilities alone.
398
+ *
399
+ * The per-member counterpart to {@link openToDelegatedExecution}, and what
400
+ * closes the gap that method cannot: a relay admitted BEFORE the default was
401
+ * set, and an admin's own node, which never receives the default at all.
402
+ *
403
+ * `account` is the member's ACCOUNT id (64 hex) as `listGroupMembers` returns
404
+ * it — for a fleet relay, the `account` the cloud reports for that node. Not
405
+ * the signing key that added them; both are 64 hex, so nothing but the source
406
+ * tells them apart.
407
+ *
408
+ * Read-modify-write, so it adds the bit rather than replacing the member's
409
+ * mask. A no-op when the member already holds it.
410
+ */
411
+ grantAuthorship(groupId: string, account: string): Promise<{
412
+ changed: boolean;
413
+ capabilities: number;
414
+ }>;
346
415
  setSubgroupVisibility(groupId: string, request: SetSubgroupVisibilityRequest): Promise<void>;
347
416
  setTeeAdmissionPolicy(groupId: string, request: SetTeeAdmissionPolicyRequest): Promise<void>;
348
417
  getTeeAdmissionPolicy(groupId: string): Promise<GetTeeAdmissionPolicyResponseData>;
@@ -1,4 +1,5 @@
1
1
  import { withRetry } from '../http-client/index.js';
2
+ import { CAPABILITIES, hasCap, withCap } from '../capabilities.js';
2
3
  /**
3
4
  * Helper: server wraps most responses in `{ data: T }`.
4
5
  * This extracts `.data` so callers get the inner payload directly. Null-safe so an
@@ -709,6 +710,85 @@ export class AdminApiClient {
709
710
  async setDefaultCapabilities(groupId, request) {
710
711
  await this.httpClient.put(`/admin-api/groups/${groupId}/settings/default-capabilities`, request);
711
712
  }
713
+ /**
714
+ * Make every member admitted to `groupId` from now on able to relay a
715
+ * delegated write, without a per-node governance op each time.
716
+ *
717
+ * `CAN_AUTHOR_ON_BEHALF` is implied by nothing — not membership, not admin —
718
+ * so every group is authorship-closed and each fleet relay otherwise needs an
719
+ * admin to grant it individually, at the moment the relay is assigned and the
720
+ * admin is not watching. Setting it in the group's DEFAULT mask is core's own
721
+ * answer to that: `add_member` seeds a non-admin's capability row from the
722
+ * default, so an attested node admitted afterwards lands open.
723
+ *
724
+ * Call it on the NAMESPACE (the root group). A grant resolves through the
725
+ * membership anchor, so one at the root reaches every Open subgroup beneath
726
+ * it, which is where contexts actually live; a `Restricted` subgroup is a
727
+ * membership boundary and needs its own call.
728
+ *
729
+ * ### Two things this does not do
730
+ *
731
+ * **It is not retroactive.** The default is copied into a member's row when
732
+ * that member is admitted, so nodes already admitted keep the row they got.
733
+ * Use {@link grantAuthorship} for those — or call this at namespace creation,
734
+ * which is the only point that needs no backfill at all.
735
+ *
736
+ * **It does not reach admins.** Core seeds the default only for non-admin
737
+ * roles, and `CAN_AUTHOR_ON_BEHALF` is deliberately not implied by admin. An
738
+ * admin's own node therefore stays closed and needs {@link grantAuthorship}.
739
+ *
740
+ * ### What it widens
741
+ *
742
+ * Every future non-admin member of the group, not only attested TEE nodes, so
743
+ * any of them may be named as a warrant's `executor`. The bound worth knowing
744
+ * before deciding: an executor cannot FORGE. A delegated write is authorized
745
+ * by the author's own warrant — signed by their device key, committed to one
746
+ * context, method and exact arguments, with its nonce checked unspent — so a
747
+ * holder can only spend a warrant it was deliberately handed. What it does
748
+ * gain is the arguments in cleartext and the choice of when, or whether, to
749
+ * publish.
750
+ *
751
+ * Read-modify-write rather than a blind set: core seeds a new group's default
752
+ * with `CAN_JOIN_OPEN_SUBGROUPS`, and overwriting that would quietly stop
753
+ * every later member inheriting into Open subgroups.
754
+ *
755
+ * Returns the resulting mask and whether an op was published — it is a no-op
756
+ * when the bit is already set, so it is safe to call on every startup.
757
+ */
758
+ async openToDelegatedExecution(groupId) {
759
+ const current = await this.getDefaultCapabilities(groupId);
760
+ if (hasCap(current, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
761
+ return { changed: false, defaultCapabilities: current };
762
+ }
763
+ const next = withCap(current, CAPABILITIES.CAN_AUTHOR_ON_BEHALF);
764
+ await this.setDefaultCapabilities(groupId, { defaultCapabilities: next });
765
+ return { changed: true, defaultCapabilities: next };
766
+ }
767
+ /**
768
+ * Grant `account` the authorship bit on `groupId`, leaving its other
769
+ * capabilities alone.
770
+ *
771
+ * The per-member counterpart to {@link openToDelegatedExecution}, and what
772
+ * closes the gap that method cannot: a relay admitted BEFORE the default was
773
+ * set, and an admin's own node, which never receives the default at all.
774
+ *
775
+ * `account` is the member's ACCOUNT id (64 hex) as `listGroupMembers` returns
776
+ * it — for a fleet relay, the `account` the cloud reports for that node. Not
777
+ * the signing key that added them; both are 64 hex, so nothing but the source
778
+ * tells them apart.
779
+ *
780
+ * Read-modify-write, so it adds the bit rather than replacing the member's
781
+ * mask. A no-op when the member already holds it.
782
+ */
783
+ async grantAuthorship(groupId, account) {
784
+ const { capabilities } = await this.getMemberCapabilities(groupId, account);
785
+ if (hasCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
786
+ return { changed: false, capabilities };
787
+ }
788
+ const next = withCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF);
789
+ await this.setMemberCapabilities(groupId, account, { capabilities: next });
790
+ return { changed: true, capabilities: next };
791
+ }
712
792
  async setSubgroupVisibility(groupId, request) {
713
793
  await this.httpClient.put(`/admin-api/groups/${groupId}/settings/subgroup-visibility`, request);
714
794
  }