shogun-core 3.2.3 → 3.3.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 +12 -0
- package/dist/browser/shogun-core.js +108102 -43579
- package/dist/browser/shogun-core.js.map +1 -1
- package/dist/ship/examples/messenger-cli.js +171 -55
- package/dist/ship/examples/wallet-cli.js +767 -0
- package/dist/ship/implementation/SHIP_00.js +478 -0
- package/dist/ship/implementation/SHIP_01.js +275 -492
- package/dist/ship/implementation/SHIP_02.js +1366 -0
- package/dist/ship/implementation/SHIP_03.js +855 -0
- package/dist/ship/interfaces/ISHIP_00.js +135 -0
- package/dist/ship/interfaces/ISHIP_01.js +81 -24
- package/dist/ship/interfaces/ISHIP_02.js +57 -0
- package/dist/ship/interfaces/ISHIP_03.js +61 -0
- package/dist/src/gundb/db.js +55 -11
- package/dist/src/index.js +10 -2
- package/dist/src/managers/CoreInitializer.js +41 -13
- package/dist/src/storage/storage.js +22 -9
- package/dist/types/ship/examples/messenger-cli.d.ts +7 -1
- package/dist/types/ship/examples/wallet-cli.d.ts +131 -0
- package/dist/types/ship/implementation/SHIP_00.d.ts +113 -0
- package/dist/types/ship/implementation/SHIP_01.d.ts +44 -77
- package/dist/types/ship/implementation/SHIP_02.d.ts +297 -0
- package/dist/types/ship/implementation/SHIP_03.d.ts +127 -0
- package/dist/types/ship/interfaces/ISHIP_00.d.ts +410 -0
- package/dist/types/ship/interfaces/ISHIP_01.d.ts +157 -119
- package/dist/types/ship/interfaces/ISHIP_02.d.ts +470 -0
- package/dist/types/ship/interfaces/ISHIP_03.d.ts +295 -0
- package/dist/types/src/gundb/db.d.ts +10 -3
- package/dist/types/src/index.d.ts +7 -0
- package/dist/types/src/interfaces/shogun.d.ts +2 -0
- package/dist/types/src/storage/storage.d.ts +2 -1
- package/package.json +22 -9
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SHIP-00: Decentralized Identity & Authentication Implementation
|
|
4
|
+
*
|
|
5
|
+
* Foundation layer for the Shogun ecosystem.
|
|
6
|
+
* Provides identity and authentication services for all other SHIPs.
|
|
7
|
+
*
|
|
8
|
+
* Based on:
|
|
9
|
+
* - Shogun Core API (see ../API.md)
|
|
10
|
+
* - GunDB for P2P identity storage
|
|
11
|
+
* - SEA for cryptographic operations
|
|
12
|
+
* - shogun-derive for address derivation
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* ✅ Username/password authentication
|
|
16
|
+
* ✅ SEA key pair management
|
|
17
|
+
* ✅ Public key publication and discovery
|
|
18
|
+
* ✅ User registry and lookup
|
|
19
|
+
* ✅ Blockchain address derivation
|
|
20
|
+
* ✅ Multi-device support (export/import)
|
|
21
|
+
*/
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.SHIP_00 = void 0;
|
|
27
|
+
const core_1 = require("../../src/core");
|
|
28
|
+
const ethers_1 = require("ethers");
|
|
29
|
+
const derive_1 = __importDefault(require("../../src/gundb/derive"));
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// IMPLEMENTATION
|
|
32
|
+
// ============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* SHIP-00 Reference Implementation
|
|
35
|
+
*
|
|
36
|
+
* Uses Shogun Core as the underlying implementation.
|
|
37
|
+
* This class wraps Shogun Core APIs to provide the ISHIP_00 standard interface.
|
|
38
|
+
*/
|
|
39
|
+
class SHIP_00 {
|
|
40
|
+
constructor(shogunConfig) {
|
|
41
|
+
// Initialize Shogun Core with provided config
|
|
42
|
+
this.shogun = new core_1.ShogunCore(shogunConfig);
|
|
43
|
+
}
|
|
44
|
+
// ========================================================================
|
|
45
|
+
// AUTHENTICATION
|
|
46
|
+
// ========================================================================
|
|
47
|
+
/**
|
|
48
|
+
* Register new user
|
|
49
|
+
* Uses Shogun Core signUp method (see API.md)
|
|
50
|
+
*/
|
|
51
|
+
async signup(username, password) {
|
|
52
|
+
try {
|
|
53
|
+
// Use Shogun Core signUp (API.md line 315-327)
|
|
54
|
+
const signupResult = await this.shogun.signUp(username, password);
|
|
55
|
+
if (!signupResult.success) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: signupResult.error || "Signup failed",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
console.log("✅ User registered");
|
|
62
|
+
console.log(` Username: ${username}`);
|
|
63
|
+
console.log(` GunDB Public Key: ${signupResult.pub}`);
|
|
64
|
+
// Derive Ethereum address using shogun-derive
|
|
65
|
+
const derivedAddress = signupResult.pub
|
|
66
|
+
? await this.deriveEthereumAddress(signupResult.pub)
|
|
67
|
+
: undefined;
|
|
68
|
+
if (derivedAddress) {
|
|
69
|
+
console.log(` Derived Address: ${derivedAddress}`);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
userPub: signupResult.pub,
|
|
74
|
+
username: username,
|
|
75
|
+
derivedAddress,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: error.message,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Login with username and password
|
|
87
|
+
* Uses Shogun Core login method (see API.md)
|
|
88
|
+
*/
|
|
89
|
+
async login(username, password) {
|
|
90
|
+
try {
|
|
91
|
+
// Use Shogun Core login (API.md line 309-317)
|
|
92
|
+
const loginResult = await this.shogun.login(username, password);
|
|
93
|
+
if (!loginResult.success) {
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
error: loginResult.error || "Login failed",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
console.log("✅ Login successful");
|
|
100
|
+
console.log(` Username: ${username}`);
|
|
101
|
+
console.log(` GunDB Public Key: ${loginResult.userPub}`);
|
|
102
|
+
// Derive Ethereum address
|
|
103
|
+
const derivedAddress = loginResult.userPub
|
|
104
|
+
? await this.deriveEthereumAddress(loginResult.userPub)
|
|
105
|
+
: undefined;
|
|
106
|
+
if (derivedAddress) {
|
|
107
|
+
console.log(` Derived Address: ${derivedAddress}`);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
success: true,
|
|
111
|
+
userPub: loginResult.userPub,
|
|
112
|
+
username: username,
|
|
113
|
+
derivedAddress,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
error: error.message,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Login with SEA Key Pair
|
|
125
|
+
* Uses Shogun Core loginWithPair method (see API.md)
|
|
126
|
+
*/
|
|
127
|
+
async loginWithPair(seaPair) {
|
|
128
|
+
try {
|
|
129
|
+
console.log("🔐 Login with key pair...");
|
|
130
|
+
// Use Shogun Core loginWithPair (API.md line 324)
|
|
131
|
+
const authResult = await this.shogun.loginWithPair(seaPair);
|
|
132
|
+
if (!authResult.success) {
|
|
133
|
+
console.log("❌ Login failed:", authResult.error);
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
error: authResult.error || "Login with pair failed",
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Derive Ethereum address
|
|
140
|
+
const derivedAddress = await this.deriveEthereumAddress(seaPair.pub);
|
|
141
|
+
console.log("✅ Login successful");
|
|
142
|
+
console.log(` GunDB Public Key: ${seaPair.pub}`);
|
|
143
|
+
console.log(` Derived Address: ${derivedAddress}`);
|
|
144
|
+
return {
|
|
145
|
+
success: true,
|
|
146
|
+
userPub: authResult.userPub,
|
|
147
|
+
username: authResult.username,
|
|
148
|
+
derivedAddress,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error("❌ Error login with pair:", error);
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Logout
|
|
161
|
+
* Uses Shogun Core logout method (see API.md line 325)
|
|
162
|
+
*/
|
|
163
|
+
logout() {
|
|
164
|
+
this.shogun.logout();
|
|
165
|
+
console.log("👋 Logout successful");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if user is logged in
|
|
169
|
+
* Uses Shogun Core isLoggedIn method (see API.md line 326)
|
|
170
|
+
*/
|
|
171
|
+
isLoggedIn() {
|
|
172
|
+
return this.shogun.isLoggedIn();
|
|
173
|
+
}
|
|
174
|
+
// ========================================================================
|
|
175
|
+
// CORE ACCESS
|
|
176
|
+
// ========================================================================
|
|
177
|
+
/**
|
|
178
|
+
* Get underlying ShogunCore instance
|
|
179
|
+
* Provides access to Gun, SEA, and crypto utilities
|
|
180
|
+
*/
|
|
181
|
+
getShogun() {
|
|
182
|
+
return this.shogun;
|
|
183
|
+
}
|
|
184
|
+
// ========================================================================
|
|
185
|
+
// KEY MANAGEMENT
|
|
186
|
+
// ========================================================================
|
|
187
|
+
/**
|
|
188
|
+
* Publish public key on GunDB
|
|
189
|
+
* Makes user's public key discoverable by others
|
|
190
|
+
*/
|
|
191
|
+
async publishPublicKey() {
|
|
192
|
+
try {
|
|
193
|
+
if (!this.isLoggedIn()) {
|
|
194
|
+
return { success: false, error: "Not logged in" };
|
|
195
|
+
}
|
|
196
|
+
// Get current user from DataBase (API.md line 374)
|
|
197
|
+
const currentUser = this.shogun.db.user;
|
|
198
|
+
if (!currentUser || !currentUser.is) {
|
|
199
|
+
return { success: false, error: "No user session" };
|
|
200
|
+
}
|
|
201
|
+
const userPub = currentUser.is.pub;
|
|
202
|
+
// Save public key to GunDB for discovery
|
|
203
|
+
// Using Gun operations (API.md line 399-406)
|
|
204
|
+
await this.shogun.db.gun
|
|
205
|
+
.get(userPub)
|
|
206
|
+
.put({
|
|
207
|
+
pub: currentUser.is.pub,
|
|
208
|
+
epub: currentUser.is.epub,
|
|
209
|
+
algorithm: "ECDSA",
|
|
210
|
+
timestamp: Date.now().toString(),
|
|
211
|
+
})
|
|
212
|
+
.then();
|
|
213
|
+
console.log(`📝 Public key published on GunDB`);
|
|
214
|
+
return { success: true };
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
console.error("❌ Error publishing key:", error);
|
|
218
|
+
return { success: false, error: error.message };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Export current user's SEA key pair
|
|
223
|
+
* For backup and multi-device usage
|
|
224
|
+
* Uses Shogun Core exportPair method (see API.md line 354)
|
|
225
|
+
*/
|
|
226
|
+
exportKeyPair() {
|
|
227
|
+
try {
|
|
228
|
+
if (!this.isLoggedIn()) {
|
|
229
|
+
console.warn("Cannot export key pair: user not logged in");
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
// Access SEA pair from Gun user node
|
|
233
|
+
const seaPair = this.shogun.db.gun.user()?._?.sea;
|
|
234
|
+
if (!seaPair) {
|
|
235
|
+
console.warn("Cannot access SEA pair");
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
pub: seaPair.pub,
|
|
240
|
+
priv: seaPair.priv,
|
|
241
|
+
epub: seaPair.epub,
|
|
242
|
+
epriv: seaPair.epriv,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
console.error("❌ Error exporting key pair:", error);
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get current user's key pair
|
|
252
|
+
* Alias for exportKeyPair()
|
|
253
|
+
*/
|
|
254
|
+
getKeyPair() {
|
|
255
|
+
return this.exportKeyPair();
|
|
256
|
+
}
|
|
257
|
+
// ========================================================================
|
|
258
|
+
// USER DISCOVERY
|
|
259
|
+
// ========================================================================
|
|
260
|
+
/**
|
|
261
|
+
* Get user information by username
|
|
262
|
+
* Uses Shogun Core getUserByAlias method (see API.md line 1141-1148)
|
|
263
|
+
*/
|
|
264
|
+
async getUserByAlias(username) {
|
|
265
|
+
try {
|
|
266
|
+
// Use DataBase getUserByAlias (API.md line 1141)
|
|
267
|
+
const userData = await this.shogun.db.getUserByAlias(username);
|
|
268
|
+
if (!userData) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
userPub: userData.userPub || "",
|
|
273
|
+
username: userData.username,
|
|
274
|
+
epub: userData.epub || "",
|
|
275
|
+
registeredAt: userData.registeredAt,
|
|
276
|
+
lastSeen: userData.lastSeen,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
console.error("❌ Error getting user by alias:", error);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Get user information by public key
|
|
286
|
+
* Uses Shogun Core getUserDataByPub method (see API.md line 1150-1152)
|
|
287
|
+
*/
|
|
288
|
+
async getUserByPub(userPub) {
|
|
289
|
+
try {
|
|
290
|
+
const userData = await this.shogun.db.getUserDataByPub(userPub);
|
|
291
|
+
if (!userData) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
userPub: userPub,
|
|
296
|
+
username: userData.username,
|
|
297
|
+
epub: userData.epub || "",
|
|
298
|
+
registeredAt: userData.registeredAt,
|
|
299
|
+
lastSeen: userData.lastSeen,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
console.error("❌ Error getting user by pub:", error);
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check if user exists
|
|
309
|
+
* Uses SimpleGunAPI userExists method (see API.md line 188)
|
|
310
|
+
*/
|
|
311
|
+
async userExists(username) {
|
|
312
|
+
try {
|
|
313
|
+
const userData = await this.getUserByAlias(username);
|
|
314
|
+
return userData !== null;
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
console.error("❌ Error checking user existence:", error);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get public key by username
|
|
323
|
+
*/
|
|
324
|
+
async getPublicKey(username) {
|
|
325
|
+
try {
|
|
326
|
+
// Get user data first
|
|
327
|
+
const userData = await this.getUserByAlias(username);
|
|
328
|
+
if (!userData || !userData.userPub) {
|
|
329
|
+
console.error(`❌ User ${username} not found`);
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
const userPub = userData.userPub;
|
|
333
|
+
// Get published public key data
|
|
334
|
+
const publicKeyData = await this.shogun.db.gun.get(userPub).then();
|
|
335
|
+
if (publicKeyData && publicKeyData.epub && publicKeyData.pub) {
|
|
336
|
+
return {
|
|
337
|
+
pub: publicKeyData.pub,
|
|
338
|
+
epub: publicKeyData.epub,
|
|
339
|
+
algorithm: publicKeyData.algorithm,
|
|
340
|
+
timestamp: publicKeyData.timestamp,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
console.error("❌ Error getting public key:", error);
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// ========================================================================
|
|
351
|
+
// IDENTITY
|
|
352
|
+
// ========================================================================
|
|
353
|
+
/**
|
|
354
|
+
* Get current authenticated user info
|
|
355
|
+
* Uses Shogun Core getCurrentUser method (see API.md line 429)
|
|
356
|
+
*/
|
|
357
|
+
getCurrentUser() {
|
|
358
|
+
try {
|
|
359
|
+
if (!this.isLoggedIn()) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
// Use DataBase getCurrentUser (API.md line 429)
|
|
363
|
+
const currentUser = this.shogun.db.getCurrentUser();
|
|
364
|
+
if (!currentUser) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
pub: currentUser.pub,
|
|
369
|
+
alias: currentUser.alias,
|
|
370
|
+
epub: currentUser.epub,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
console.error("❌ Error getting current user:", error);
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Derive Ethereum address from SEA keypair
|
|
380
|
+
* Uses shogun-derive package for deterministic derivation
|
|
381
|
+
*/
|
|
382
|
+
async deriveEthereumAddress(publicKey) {
|
|
383
|
+
try {
|
|
384
|
+
// Get SEA pair
|
|
385
|
+
const seaPair = this.shogun.db.gun.user()?._?.sea;
|
|
386
|
+
if (!seaPair || !seaPair.priv) {
|
|
387
|
+
throw new Error("Cannot access SEA pair");
|
|
388
|
+
}
|
|
389
|
+
// Use shogun-derive for deterministic address derivation
|
|
390
|
+
const derived = await (0, derive_1.default)(seaPair.priv, null, {
|
|
391
|
+
includeSecp256k1Ethereum: true,
|
|
392
|
+
includeP256: false,
|
|
393
|
+
includeSecp256k1Bitcoin: false,
|
|
394
|
+
});
|
|
395
|
+
return derived.secp256k1Ethereum.address;
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
console.error("❌ Error deriving address:", error);
|
|
399
|
+
// Fallback: hash of public key
|
|
400
|
+
const fallbackKey = publicKey || "unknown";
|
|
401
|
+
const hash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(fallbackKey));
|
|
402
|
+
return ethers_1.ethers.getAddress("0x" + hash.slice(-40));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
exports.SHIP_00 = SHIP_00;
|
|
407
|
+
// GunDB Node Names for identity storage
|
|
408
|
+
// Note: Most operations use ShogunCore API which manages nodes internally
|
|
409
|
+
// These are reference names for direct Gun access when needed
|
|
410
|
+
SHIP_00.NODES = {
|
|
411
|
+
USERS: "users", // User registry
|
|
412
|
+
PUBLIC_KEYS: "publicKeys", // Public key directory
|
|
413
|
+
REGISTRY: "registry", // User alias → pub mapping
|
|
414
|
+
};
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// EXAMPLE & TESTING
|
|
417
|
+
// ============================================================================
|
|
418
|
+
/**
|
|
419
|
+
* Example usage of SHIP-00
|
|
420
|
+
*/
|
|
421
|
+
async function exampleUsage() {
|
|
422
|
+
console.log("🧪 SHIP-00 Example: Identity Management\n");
|
|
423
|
+
console.log("=".repeat(60));
|
|
424
|
+
// Initialize
|
|
425
|
+
const identity = new SHIP_00({
|
|
426
|
+
gunOptions: {
|
|
427
|
+
peers: ["https://peer.wallie.io/gun"],
|
|
428
|
+
radisk: true,
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
// Signup
|
|
432
|
+
console.log("\n📝 SIGNUP");
|
|
433
|
+
console.log("-".repeat(60));
|
|
434
|
+
const signupResult = await identity.signup("alice", "password123");
|
|
435
|
+
if (signupResult.success) {
|
|
436
|
+
console.log("✅ Signup successful");
|
|
437
|
+
console.log(` Username: ${signupResult.username}`);
|
|
438
|
+
console.log(` Public Key: ${signupResult.userPub?.substring(0, 40)}...`);
|
|
439
|
+
console.log(` Ethereum Address: ${signupResult.derivedAddress}`);
|
|
440
|
+
}
|
|
441
|
+
// Publish public key
|
|
442
|
+
console.log("\n📢 PUBLISH PUBLIC KEY");
|
|
443
|
+
console.log("-".repeat(60));
|
|
444
|
+
await identity.publishPublicKey();
|
|
445
|
+
// Export key pair
|
|
446
|
+
console.log("\n💾 EXPORT KEY PAIR");
|
|
447
|
+
console.log("-".repeat(60));
|
|
448
|
+
const keyPair = identity.exportKeyPair();
|
|
449
|
+
if (keyPair) {
|
|
450
|
+
const backup = Buffer.from(JSON.stringify(keyPair)).toString('base64');
|
|
451
|
+
console.log("✅ Key pair exported (base64)");
|
|
452
|
+
console.log(` Length: ${backup.length} characters`);
|
|
453
|
+
}
|
|
454
|
+
// Current user
|
|
455
|
+
console.log("\n👤 CURRENT USER");
|
|
456
|
+
console.log("-".repeat(60));
|
|
457
|
+
const currentUser = identity.getCurrentUser();
|
|
458
|
+
console.log("Current user:", currentUser?.alias);
|
|
459
|
+
console.log("Public key:", currentUser?.pub.substring(0, 40) + "...");
|
|
460
|
+
// User discovery
|
|
461
|
+
console.log("\n🔍 USER DISCOVERY");
|
|
462
|
+
console.log("-".repeat(60));
|
|
463
|
+
const exists = await identity.userExists("alice");
|
|
464
|
+
console.log("Alice exists:", exists);
|
|
465
|
+
const aliceData = await identity.getUserByAlias("alice");
|
|
466
|
+
console.log("Alice data:", aliceData?.username);
|
|
467
|
+
// Logout
|
|
468
|
+
console.log("\n👋 LOGOUT");
|
|
469
|
+
console.log("-".repeat(60));
|
|
470
|
+
identity.logout();
|
|
471
|
+
console.log("Logged out successfully");
|
|
472
|
+
console.log("\n" + "=".repeat(60));
|
|
473
|
+
console.log("✅ SHIP-00 Example Complete!\n");
|
|
474
|
+
}
|
|
475
|
+
// Run example if executed directly
|
|
476
|
+
if (require.main === module) {
|
|
477
|
+
exampleUsage().catch(console.error);
|
|
478
|
+
}
|