@calimero-network/mero-js 19.5.0 → 19.6.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
+ ];
@@ -134,6 +134,52 @@ export interface CloudMachine {
134
134
  /** Only the caller's own namespaces, even on a machine shared with others. */
135
135
  namespaces: CloudMachineNamespace[];
136
136
  }
137
+ /** A Calimero account linked to this cloud login. */
138
+ export interface CloudLinkedAccount {
139
+ /** The account id, 64 hex. */
140
+ accountId: string;
141
+ linkedAt?: string | null;
142
+ /**
143
+ * Whether a recovery envelope has been stored for this account, so a UI can
144
+ * say "recoverable" without fetching the blob.
145
+ */
146
+ hasRecoveryEnvelope: boolean;
147
+ }
148
+ /** What {@link CloudClient.getMyAccounts} reports. */
149
+ export interface CloudLinkedAccounts {
150
+ accounts: CloudLinkedAccount[];
151
+ /** How many the caller's plan allows. `null` means no limit. */
152
+ limit: number | null;
153
+ }
154
+ /** A single-use challenge to sign with an account root. */
155
+ export interface AccountLinkChallenge {
156
+ /** Sign this verbatim — it is an opaque sealed string, not a decodable id. */
157
+ nonce: string;
158
+ /** When it stops being accepted, epoch milliseconds. */
159
+ expiresAtMs: number | null;
160
+ }
161
+ /** A proof assembled by whoever holds the root, for {@link CloudClient.submitAccountLink}. */
162
+ export interface AccountLinkProof {
163
+ /** The account being claimed, 64 hex. */
164
+ accountId: string;
165
+ /** The root that names it, 64 hex. */
166
+ rootPublicKey: string;
167
+ /** The challenge that was signed. */
168
+ nonce: string;
169
+ /** `signAccountLink`'s output — standard base64. */
170
+ signature: string;
171
+ }
172
+ /** The outcome of {@link CloudClient.linkAccount}. */
173
+ export interface CloudAccountLink {
174
+ accountId: string;
175
+ linkedAt?: string | null;
176
+ /**
177
+ * True when this account was already linked to this same login, which the
178
+ * cloud treats as a 200 no-op rather than an error. A caller re-running
179
+ * onboarding gets success, not a confusing failure.
180
+ */
181
+ alreadyLinked: boolean;
182
+ }
137
183
  export interface EnableHAOptions {
138
184
  groupId: string;
139
185
  contextId: string;
@@ -265,6 +311,53 @@ export declare class CloudClient {
265
311
  enableHA(options: EnableHAOptions): void;
266
312
  disableHA(options: DisableHAOptions): void;
267
313
  /** Record a freshly-issued session and tell the app to persist it. */
314
+ /**
315
+ * Link a Calimero account to this cloud login, proving possession of its root.
316
+ *
317
+ * Two hops, folded into one call because they are useless apart: fetch a
318
+ * single-use challenge, then sign it with the account root and post the proof.
319
+ * The secret never leaves this process — only a signature over a nonce the
320
+ * cloud minted does.
321
+ *
322
+ * This is the binding the cloud bills against. A relay does not need it to run
323
+ * an intent; the cloud needs it to know whose plan a hosted node is spending,
324
+ * and to sign that account back in later.
325
+ *
326
+ * @param rootSecret the account root's signing secret, 64 hex — from
327
+ * {@link generateAccountRoot}, from a restored recovery phrase, or from a
328
+ * desktop app or hardware key that already holds one.
329
+ *
330
+ * Idempotent for the same login. An account already linked to a *different*
331
+ * cloud login is a `409`; a replayed or expired challenge is a `403`; and
332
+ * exceeding the plan's account limit is a `402`.
333
+ */
334
+ linkAccount(rootSecret: string): Promise<CloudAccountLink>;
335
+ /**
336
+ * Mint a single-use challenge for an account root to sign.
337
+ *
338
+ * The split half of {@link linkAccount}, for the case that call cannot serve:
339
+ * a root held by a desktop app, a hardware key or an air-gapped machine, which
340
+ * signs without the secret ever reaching this process. Fetch the challenge
341
+ * here, have the holder sign it, then hand the proof to
342
+ * {@link submitAccountLink}.
343
+ *
344
+ * Bound to the signed-in login and short-lived, so it is not a standing
345
+ * capability if it leaks — but it IS single-use, so a challenge fetched and
346
+ * abandoned is spent.
347
+ */
348
+ getAccountLinkChallenge(): Promise<AccountLinkChallenge>;
349
+ /**
350
+ * Post a proof assembled elsewhere. The other half of
351
+ * {@link getAccountLinkChallenge}.
352
+ *
353
+ * `accountId` must be the account `rootPublicKey` names — the cloud refuses a
354
+ * valid signature by a key that names a different account, or a caller could
355
+ * prove one root and link somebody else's account. Derive both from the same
356
+ * key rather than letting a user type either.
357
+ */
358
+ submitAccountLink(proof: AccountLinkProof): Promise<CloudAccountLink>;
359
+ /** The accounts linked to this login, and how many the plan allows. */
360
+ getMyAccounts(): Promise<CloudLinkedAccounts>;
268
361
  private adoptSession;
269
362
  private notifySession;
270
363
  private request;
@@ -24,6 +24,7 @@
24
24
  * ever sent, and would be a throughput bottleneck on a path that has no reason
25
25
  * to involve it.
26
26
  */
27
+ import { accountRootFromSecret, signAccountLink, } from '../account/index.js';
27
28
  import { HTTPError } from '../http-client/web-client.js';
28
29
  /** Where the hosted cloud lives when a caller names no other. */
29
30
  const DEFAULT_CLOUD_BASE_URL = 'https://cloud.calimero.network';
@@ -260,6 +261,89 @@ export class CloudClient {
260
261
  window.open(`${this.baseUrl}/disable-ha?${params.toString()}`);
261
262
  }
262
263
  /** Record a freshly-issued session and tell the app to persist it. */
264
+ /**
265
+ * Link a Calimero account to this cloud login, proving possession of its root.
266
+ *
267
+ * Two hops, folded into one call because they are useless apart: fetch a
268
+ * single-use challenge, then sign it with the account root and post the proof.
269
+ * The secret never leaves this process — only a signature over a nonce the
270
+ * cloud minted does.
271
+ *
272
+ * This is the binding the cloud bills against. A relay does not need it to run
273
+ * an intent; the cloud needs it to know whose plan a hosted node is spending,
274
+ * and to sign that account back in later.
275
+ *
276
+ * @param rootSecret the account root's signing secret, 64 hex — from
277
+ * {@link generateAccountRoot}, from a restored recovery phrase, or from a
278
+ * desktop app or hardware key that already holds one.
279
+ *
280
+ * Idempotent for the same login. An account already linked to a *different*
281
+ * cloud login is a `409`; a replayed or expired challenge is a `403`; and
282
+ * exceeding the plan's account limit is a `402`.
283
+ */
284
+ async linkAccount(rootSecret) {
285
+ const root = await accountRootFromSecret(rootSecret);
286
+ const { nonce } = await this.getAccountLinkChallenge();
287
+ return this.submitAccountLink({
288
+ accountId: root.accountId,
289
+ rootPublicKey: root.publicKey,
290
+ nonce,
291
+ signature: await signAccountLink({ rootSecret, nonce }),
292
+ });
293
+ }
294
+ /**
295
+ * Mint a single-use challenge for an account root to sign.
296
+ *
297
+ * The split half of {@link linkAccount}, for the case that call cannot serve:
298
+ * a root held by a desktop app, a hardware key or an air-gapped machine, which
299
+ * signs without the secret ever reaching this process. Fetch the challenge
300
+ * here, have the holder sign it, then hand the proof to
301
+ * {@link submitAccountLink}.
302
+ *
303
+ * Bound to the signed-in login and short-lived, so it is not a standing
304
+ * capability if it leaks — but it IS single-use, so a challenge fetched and
305
+ * abandoned is spent.
306
+ */
307
+ async getAccountLinkChallenge() {
308
+ const body = await this.request('GET', '/api/cloud/me/accounts/challenge');
309
+ return { nonce: body.nonce, expiresAtMs: body.expires_at_ms ?? null };
310
+ }
311
+ /**
312
+ * Post a proof assembled elsewhere. The other half of
313
+ * {@link getAccountLinkChallenge}.
314
+ *
315
+ * `accountId` must be the account `rootPublicKey` names — the cloud refuses a
316
+ * valid signature by a key that names a different account, or a caller could
317
+ * prove one root and link somebody else's account. Derive both from the same
318
+ * key rather than letting a user type either.
319
+ */
320
+ async submitAccountLink(proof) {
321
+ const body = await this.request('POST', '/api/cloud/me/accounts', {
322
+ body: {
323
+ account_id: proof.accountId,
324
+ root_public_key: proof.rootPublicKey,
325
+ nonce: proof.nonce,
326
+ signature: proof.signature,
327
+ },
328
+ });
329
+ return {
330
+ accountId: String(body.account_id ?? proof.accountId),
331
+ linkedAt: body.linked_at ?? null,
332
+ alreadyLinked: body.already_linked === true,
333
+ };
334
+ }
335
+ /** The accounts linked to this login, and how many the plan allows. */
336
+ async getMyAccounts() {
337
+ const body = await this.request('GET', '/api/cloud/me/accounts');
338
+ return {
339
+ accounts: (body.accounts ?? []).map((row) => ({
340
+ accountId: String(row.account_id ?? ''),
341
+ linkedAt: row.linked_at ?? null,
342
+ hasRecoveryEnvelope: row.has_recovery_envelope === true,
343
+ })),
344
+ limit: body.limit ?? null,
345
+ };
346
+ }
263
347
  adoptSession(body) {
264
348
  this.session = {
265
349
  sessionToken: body.session_token,
@@ -1,4 +1,4 @@
1
1
  export { CloudClient } from './cloud-client.js';
2
- export type { CloudClientConfig, CloudSession, CloudNamespace, CloudRelay, CloudMachine, CloudMachineNamespace, EnableHAOptions, DisableHAOptions, } from './cloud-client.js';
2
+ export type { CloudClientConfig, CloudSession, CloudNamespace, CloudRelay, CloudMachine, CloudMachineNamespace, CloudLinkedAccount, CloudLinkedAccounts, CloudAccountLink, AccountLinkChallenge, AccountLinkProof, EnableHAOptions, DisableHAOptions, } from './cloud-client.js';
3
3
  export { connectCloud } from './connect.js';
4
4
  export type { ConnectCloudOptions, CloudConnection } from './connect.js';