shogun-core 2.0.4 → 3.0.1

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.
@@ -1,2 +1,6 @@
1
1
  // Export the main class
2
2
  export * from "./db";
3
+ // Export improved types
4
+ export * from "./types";
5
+ // Export simplified API
6
+ export * from "./simple-api";
@@ -0,0 +1,438 @@
1
+ /**
2
+ * Simplified API layer to reduce complexity for common use cases
3
+ * Provides quick-start methods that wrap the full DataBase functionality
4
+ */
5
+ import { DataBase } from "./db";
6
+ /**
7
+ * Simple API wrapper that provides common operations with minimal complexity
8
+ */
9
+ export class SimpleGunAPI {
10
+ db;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ /**
15
+ * Quick data operations - simplified interface
16
+ */
17
+ // Simple get - returns data directly or null
18
+ async get(path) {
19
+ try {
20
+ const result = await this.db.getData(path);
21
+ return result;
22
+ }
23
+ catch (error) {
24
+ console.warn(`Failed to get data from ${path}:`, error);
25
+ return null;
26
+ }
27
+ }
28
+ // Simple put - returns success boolean
29
+ async put(path, data) {
30
+ try {
31
+ const result = await this.db.put(path, data);
32
+ return result.success;
33
+ }
34
+ catch (error) {
35
+ console.warn(`Failed to put data to ${path}:`, error);
36
+ return false;
37
+ }
38
+ }
39
+ // Simple set - returns success boolean
40
+ async set(path, data) {
41
+ try {
42
+ const result = await this.db.set(path, data);
43
+ return result.success;
44
+ }
45
+ catch (error) {
46
+ console.warn(`Failed to set data to ${path}:`, error);
47
+ return false;
48
+ }
49
+ }
50
+ // Simple remove - returns success boolean
51
+ async remove(path) {
52
+ try {
53
+ const result = await this.db.remove(path);
54
+ return result.success;
55
+ }
56
+ catch (error) {
57
+ console.warn(`Failed to remove data from ${path}:`, error);
58
+ return false;
59
+ }
60
+ }
61
+ /**
62
+ * Quick authentication - simplified interface
63
+ */
64
+ // Simple login - returns user info or null
65
+ async login(username, password) {
66
+ try {
67
+ const result = await this.db.login(username, password);
68
+ if (result.success && result.userPub) {
69
+ return {
70
+ userPub: result.userPub,
71
+ username: result.username || username,
72
+ };
73
+ }
74
+ return null;
75
+ }
76
+ catch (error) {
77
+ console.warn(`Login failed for ${username}:`, error);
78
+ return null;
79
+ }
80
+ }
81
+ // Simple signup - returns user info or null
82
+ async signup(username, password) {
83
+ try {
84
+ const result = await this.db.signUp(username, password);
85
+ if (result.success && result.userPub) {
86
+ return {
87
+ userPub: result.userPub,
88
+ username: result.username || username,
89
+ };
90
+ }
91
+ return null;
92
+ }
93
+ catch (error) {
94
+ console.warn(`Signup failed for ${username}:`, error);
95
+ return null;
96
+ }
97
+ }
98
+ // Simple logout
99
+ logout() {
100
+ this.db.logout();
101
+ }
102
+ // Simple check if logged in
103
+ isLoggedIn() {
104
+ return this.db.isLoggedIn();
105
+ }
106
+ /**
107
+ * Quick user data operations - simplified interface
108
+ */
109
+ // Simple user data get
110
+ async getUserData(path) {
111
+ try {
112
+ if (!this.isLoggedIn()) {
113
+ console.warn("User not logged in");
114
+ return null;
115
+ }
116
+ return (await this.db.getUserData(path));
117
+ }
118
+ catch (error) {
119
+ console.warn(`Failed to get user data from ${path}:`, error);
120
+ return null;
121
+ }
122
+ }
123
+ // Simple user data put
124
+ async putUserData(path, data) {
125
+ try {
126
+ if (!this.isLoggedIn()) {
127
+ console.warn("User not logged in");
128
+ return false;
129
+ }
130
+ await this.db.putUserData(path, data);
131
+ return true;
132
+ }
133
+ catch (error) {
134
+ console.warn(`Failed to put user data to ${path}:`, error);
135
+ return false;
136
+ }
137
+ }
138
+ // Simple user data set (alternative to put)
139
+ async setUserData(path, data) {
140
+ try {
141
+ if (!this.isLoggedIn()) {
142
+ console.warn("User not logged in");
143
+ return false;
144
+ }
145
+ // Use the user's gun instance directly for set operations
146
+ const user = this.db.getUser();
147
+ if (user && user.is) {
148
+ await new Promise((resolve, reject) => {
149
+ user.get(path).set(data, (ack) => {
150
+ if (ack.err) {
151
+ reject(new Error(ack.err));
152
+ }
153
+ else {
154
+ resolve();
155
+ }
156
+ });
157
+ });
158
+ return true;
159
+ }
160
+ return false;
161
+ }
162
+ catch (error) {
163
+ console.warn(`Failed to set user data to ${path}:`, error);
164
+ return false;
165
+ }
166
+ }
167
+ // Simple user data remove
168
+ async removeUserData(path) {
169
+ try {
170
+ if (!this.isLoggedIn()) {
171
+ console.warn("User not logged in");
172
+ return false;
173
+ }
174
+ const user = this.db.getUser();
175
+ if (user && user.is) {
176
+ await new Promise((resolve, reject) => {
177
+ user.get(path).put(null, (ack) => {
178
+ if (ack.err) {
179
+ reject(new Error(ack.err));
180
+ }
181
+ else {
182
+ resolve();
183
+ }
184
+ });
185
+ });
186
+ return true;
187
+ }
188
+ return false;
189
+ }
190
+ catch (error) {
191
+ console.warn(`Failed to remove user data from ${path}:`, error);
192
+ return false;
193
+ }
194
+ }
195
+ /**
196
+ * Quick utility methods
197
+ */
198
+ // Get current user info
199
+ getCurrentUser() {
200
+ const user = this.db.getCurrentUser();
201
+ if (user) {
202
+ return {
203
+ pub: user.pub,
204
+ username: user.username,
205
+ };
206
+ }
207
+ return null;
208
+ }
209
+ // Check if user exists by alias
210
+ async userExists(alias) {
211
+ try {
212
+ const user = await this.db.getUserByAlias(alias);
213
+ return user !== null;
214
+ }
215
+ catch (error) {
216
+ console.warn(`Failed to check if user exists: ${alias}`, error);
217
+ return false;
218
+ }
219
+ }
220
+ // Get user by alias
221
+ async getUser(alias) {
222
+ try {
223
+ const user = await this.db.getUserByAlias(alias);
224
+ if (user) {
225
+ return {
226
+ userPub: user.userPub,
227
+ username: user.username,
228
+ };
229
+ }
230
+ return null;
231
+ }
232
+ catch (error) {
233
+ console.warn(`Failed to get user: ${alias}`, error);
234
+ return null;
235
+ }
236
+ }
237
+ /**
238
+ * Advanced user space operations
239
+ */
240
+ // Get all user data (returns user's entire data tree)
241
+ async getAllUserData() {
242
+ try {
243
+ if (!this.isLoggedIn()) {
244
+ console.warn("User not logged in");
245
+ return null;
246
+ }
247
+ const user = this.db.getUser();
248
+ if (user && user.is) {
249
+ const userData = await new Promise((resolve, reject) => {
250
+ user.once((data) => {
251
+ resolve(data);
252
+ });
253
+ });
254
+ return userData;
255
+ }
256
+ return null;
257
+ }
258
+ catch (error) {
259
+ console.warn("Failed to get all user data:", error);
260
+ return null;
261
+ }
262
+ }
263
+ // Update user profile (common use case)
264
+ async updateProfile(profileData) {
265
+ try {
266
+ if (!this.isLoggedIn()) {
267
+ console.warn("User not logged in");
268
+ return false;
269
+ }
270
+ return await this.putUserData("profile", profileData);
271
+ }
272
+ catch (error) {
273
+ console.warn("Failed to update profile:", error);
274
+ return false;
275
+ }
276
+ }
277
+ // Get user profile
278
+ async getProfile() {
279
+ try {
280
+ if (!this.isLoggedIn()) {
281
+ console.warn("User not logged in");
282
+ return null;
283
+ }
284
+ return await this.getUserData("profile");
285
+ }
286
+ catch (error) {
287
+ console.warn("Failed to get profile:", error);
288
+ return null;
289
+ }
290
+ }
291
+ // Save user settings
292
+ async saveSettings(settings) {
293
+ try {
294
+ if (!this.isLoggedIn()) {
295
+ console.warn("User not logged in");
296
+ return false;
297
+ }
298
+ return await this.putUserData("settings", settings);
299
+ }
300
+ catch (error) {
301
+ console.warn("Failed to save settings:", error);
302
+ return false;
303
+ }
304
+ }
305
+ // Get user settings
306
+ async getSettings() {
307
+ try {
308
+ if (!this.isLoggedIn()) {
309
+ console.warn("User not logged in");
310
+ return null;
311
+ }
312
+ return await this.getUserData("settings");
313
+ }
314
+ catch (error) {
315
+ console.warn("Failed to get settings:", error);
316
+ return null;
317
+ }
318
+ }
319
+ // Save user preferences
320
+ async savePreferences(preferences) {
321
+ try {
322
+ if (!this.isLoggedIn()) {
323
+ console.warn("User not logged in");
324
+ return false;
325
+ }
326
+ return await this.putUserData("preferences", preferences);
327
+ }
328
+ catch (error) {
329
+ console.warn("Failed to save preferences:", error);
330
+ return false;
331
+ }
332
+ }
333
+ // Get user preferences
334
+ async getPreferences() {
335
+ try {
336
+ if (!this.isLoggedIn()) {
337
+ console.warn("User not logged in");
338
+ return null;
339
+ }
340
+ return await this.getUserData("preferences");
341
+ }
342
+ catch (error) {
343
+ console.warn("Failed to get preferences:", error);
344
+ return null;
345
+ }
346
+ }
347
+ // Create a user collection (for storing multiple items)
348
+ async createCollection(collectionName, items) {
349
+ try {
350
+ if (!this.isLoggedIn()) {
351
+ console.warn("User not logged in");
352
+ return false;
353
+ }
354
+ return await this.putUserData(`collections/${collectionName}`, items);
355
+ }
356
+ catch (error) {
357
+ console.warn(`Failed to create collection ${collectionName}:`, error);
358
+ return false;
359
+ }
360
+ }
361
+ // Add item to collection
362
+ async addToCollection(collectionName, itemId, item) {
363
+ try {
364
+ if (!this.isLoggedIn()) {
365
+ console.warn("User not logged in");
366
+ return false;
367
+ }
368
+ return await this.putUserData(`collections/${collectionName}/${itemId}`, item);
369
+ }
370
+ catch (error) {
371
+ console.warn(`Failed to add item to collection ${collectionName}:`, error);
372
+ return false;
373
+ }
374
+ }
375
+ // Get collection
376
+ async getCollection(collectionName) {
377
+ try {
378
+ if (!this.isLoggedIn()) {
379
+ console.warn("User not logged in");
380
+ return null;
381
+ }
382
+ return await this.getUserData(`collections/${collectionName}`);
383
+ }
384
+ catch (error) {
385
+ console.warn(`Failed to get collection ${collectionName}:`, error);
386
+ return null;
387
+ }
388
+ }
389
+ // Remove item from collection
390
+ async removeFromCollection(collectionName, itemId) {
391
+ try {
392
+ if (!this.isLoggedIn()) {
393
+ console.warn("User not logged in");
394
+ return false;
395
+ }
396
+ return await this.removeUserData(`collections/${collectionName}/${itemId}`);
397
+ }
398
+ catch (error) {
399
+ console.warn(`Failed to remove item from collection ${collectionName}:`, error);
400
+ return false;
401
+ }
402
+ }
403
+ }
404
+ /**
405
+ * Factory function to create a simple API instance
406
+ */
407
+ export function createSimpleAPI(db) {
408
+ return new SimpleGunAPI(db);
409
+ }
410
+ /**
411
+ * Quick start helper - creates a simple API with minimal configuration
412
+ */
413
+ export class QuickStart {
414
+ db;
415
+ simpleAPI;
416
+ constructor(gunInstance, appScope = "shogun") {
417
+ this.db = new DataBase(gunInstance, appScope);
418
+ this.simpleAPI = new SimpleGunAPI(this.db);
419
+ }
420
+ // Initialize the database
421
+ async init() {
422
+ await this.db.initialize();
423
+ }
424
+ // Get the simple API
425
+ get api() {
426
+ return this.simpleAPI;
427
+ }
428
+ // Get the full database instance for advanced usage
429
+ get database() {
430
+ return this.db;
431
+ }
432
+ }
433
+ /**
434
+ * Global helper for quick setup
435
+ */
436
+ export function quickStart(gunInstance, appScope) {
437
+ return new QuickStart(gunInstance, appScope);
438
+ }
package/dist/index.js CHANGED
@@ -1,10 +1,16 @@
1
1
  import { ShogunCore } from "./core";
2
2
  import { SEA, RxJS, crypto, derive, GunErrors, DataBase } from "./gundb/db";
3
+ // Import Simple API and improved types
4
+ import { SimpleGunAPI, QuickStart, quickStart, createSimpleAPI, } from "./gundb";
3
5
  // Import Gun as default export
4
6
  import Gun from "./gundb/db";
5
7
  export * from "./utils/errorHandler";
6
8
  export * from "./plugins";
7
9
  export * from "./interfaces/shogun";
8
- export { SEA, RxJS, crypto, derive, GunErrors, DataBase };
10
+ // Export simplified configuration
11
+ export * from "./config/simplified-config";
12
+ export { SEA, RxJS, crypto, derive, GunErrors, DataBase,
13
+ // Simple API exports
14
+ SimpleGunAPI, QuickStart, quickStart, createSimpleAPI, };
9
15
  export { Gun };
10
16
  export { ShogunCore };
@@ -0,0 +1,225 @@
1
+ import { ErrorHandler, ErrorType } from "../utils/errorHandler";
2
+ /**
3
+ * Manages authentication operations for ShogunCore
4
+ */
5
+ export class AuthManager {
6
+ core;
7
+ currentAuthMethod;
8
+ constructor(core) {
9
+ this.core = core;
10
+ }
11
+ /**
12
+ * Check if user is logged in
13
+ * @returns {boolean} True if user is logged in, false otherwise
14
+ * @description Verifies authentication status by checking GunInstance login state
15
+ * and presence of authentication credentials in storage
16
+ */
17
+ isLoggedIn() {
18
+ return this.core.db.isLoggedIn();
19
+ }
20
+ /**
21
+ * Perform user logout
22
+ * @description Logs out the current user from GunInstance and emits logout event.
23
+ * If user is not authenticated, the logout operation is ignored.
24
+ */
25
+ logout() {
26
+ try {
27
+ if (!this.isLoggedIn()) {
28
+ return;
29
+ }
30
+ this.core.db.logout();
31
+ this.core.emit("auth:logout");
32
+ }
33
+ catch (error) {
34
+ ErrorHandler.handle(ErrorType.AUTHENTICATION, "LOGOUT_FAILED", error instanceof Error ? error.message : "Error during logout", error);
35
+ }
36
+ }
37
+ /**
38
+ * Authenticate user with username and password
39
+ * @param username - Username
40
+ * @param password - User password
41
+ * @returns {Promise<AuthResult>} Promise with authentication result
42
+ * @description Attempts to log in user with provided credentials.
43
+ * Emits login event on success.
44
+ */
45
+ async login(username, password, pair) {
46
+ try {
47
+ if (!this.currentAuthMethod) {
48
+ this.currentAuthMethod = "password";
49
+ }
50
+ const result = await this.core.db.login(username, password, pair);
51
+ if (result.success) {
52
+ // Include SEA pair in the response
53
+ const seaPair = this.core.user?._?.sea;
54
+ if (seaPair) {
55
+ result.sea = seaPair;
56
+ }
57
+ this.core.emit("auth:login", {
58
+ userPub: result.userPub ?? "",
59
+ method: this.currentAuthMethod === "pair"
60
+ ? "password"
61
+ : this.currentAuthMethod || "password",
62
+ });
63
+ }
64
+ else {
65
+ result.error = result.error || "Wrong user or password";
66
+ }
67
+ return result;
68
+ }
69
+ catch (error) {
70
+ ErrorHandler.handle(ErrorType.AUTHENTICATION, "LOGIN_FAILED", error.message ?? "Unknown error during login", error);
71
+ return {
72
+ success: false,
73
+ error: error.message ?? "Unknown error during login",
74
+ };
75
+ }
76
+ }
77
+ /**
78
+ * Login with GunDB pair directly
79
+ * @param pair - GunDB SEA pair for authentication
80
+ * @returns {Promise<AuthResult>} Promise with authentication result
81
+ * @description Authenticates user using a GunDB pair directly.
82
+ * Emits login event on success.
83
+ */
84
+ async loginWithPair(pair) {
85
+ try {
86
+ if (!pair || !pair.pub || !pair.priv || !pair.epub || !pair.epriv) {
87
+ return {
88
+ success: false,
89
+ error: "Invalid pair structure - missing required keys",
90
+ };
91
+ }
92
+ // Use the new loginWithPair method from GunInstance
93
+ const result = await this.core.db.login("", "", pair);
94
+ if (result.success) {
95
+ // Include SEA pair in the response
96
+ const seaPair = this.core.user?._?.sea;
97
+ if (seaPair) {
98
+ result.sea = seaPair;
99
+ }
100
+ this.currentAuthMethod = "pair";
101
+ this.core.emit("auth:login", {
102
+ userPub: result.userPub ?? "",
103
+ method: "password",
104
+ });
105
+ }
106
+ else {
107
+ result.error =
108
+ result.error || "Authentication failed with provided pair";
109
+ }
110
+ return result;
111
+ }
112
+ catch (error) {
113
+ ErrorHandler.handle(ErrorType.AUTHENTICATION, "PAIR_LOGIN_FAILED", error.message ?? "Unknown error during pair login", error);
114
+ return {
115
+ success: false,
116
+ error: error.message ?? "Unknown error during pair login",
117
+ };
118
+ }
119
+ }
120
+ /**
121
+ * Register a new user with provided credentials
122
+ * @param username - Username
123
+ * @param password - Password
124
+ * @param email - Email (optional)
125
+ * @param pair - Pair of keys
126
+ * @returns {Promise<SignUpResult>} Registration result
127
+ * @description Creates a new user account with the provided credentials.
128
+ * Validates password requirements and emits signup event on success.
129
+ */
130
+ async signUp(username, password, pair) {
131
+ try {
132
+ if (!this.core.db) {
133
+ throw new Error("Database not initialized");
134
+ }
135
+ // For password-based signup, ensure password is provided
136
+ if (!pair && (!password || password.trim() === "")) {
137
+ throw new Error("Password is required for password-based signup");
138
+ }
139
+ const result = await this.core.db.signUp(username, password || "", pair);
140
+ if (result.success) {
141
+ // Update current authentication method
142
+ this.currentAuthMethod = pair ? "web3" : "password";
143
+ this.core.emit("auth:signup", {
144
+ userPub: result.userPub,
145
+ username,
146
+ method: this.currentAuthMethod,
147
+ });
148
+ this.core.emit("debug", {
149
+ action: "signup_success",
150
+ userPub: result.userPub,
151
+ method: this.currentAuthMethod,
152
+ });
153
+ }
154
+ else {
155
+ this.core.emit("debug", {
156
+ action: "signup_failed",
157
+ error: result.error,
158
+ username,
159
+ });
160
+ }
161
+ return result;
162
+ }
163
+ catch (error) {
164
+ if (typeof console !== "undefined" && console.error) {
165
+ console.error(`Error during registration for user ${username}:`, error);
166
+ }
167
+ this.core.emit("debug", {
168
+ action: "signup_error",
169
+ error: error instanceof Error ? error.message : String(error),
170
+ username,
171
+ });
172
+ return {
173
+ success: false,
174
+ error: `Registration failed: ${error instanceof Error ? error.message : String(error)}`,
175
+ };
176
+ }
177
+ }
178
+ /**
179
+ * Set the current authentication method
180
+ * This is used by plugins to indicate which authentication method was used
181
+ * @param method The authentication method used
182
+ */
183
+ setAuthMethod(method) {
184
+ this.currentAuthMethod = method;
185
+ }
186
+ /**
187
+ * Get the current authentication method
188
+ * @returns The current authentication method or undefined if not set
189
+ */
190
+ getAuthMethod() {
191
+ return this.currentAuthMethod;
192
+ }
193
+ /**
194
+ * Get an authentication method plugin by type
195
+ * @param type The type of authentication method
196
+ * @returns The authentication plugin or undefined if not available
197
+ * This is a more modern approach to accessing authentication methods
198
+ */
199
+ getAuthenticationMethod(type) {
200
+ switch (type) {
201
+ case "webauthn":
202
+ return this.core.getPlugin("WebAuthn");
203
+ case "web3":
204
+ return this.core.getPlugin("Web3");
205
+ case "nostr":
206
+ return this.core.getPlugin("Nostr");
207
+ case "oauth":
208
+ return this.core.getPlugin("OAuth");
209
+ case "password":
210
+ default:
211
+ return {
212
+ login: async (username, password) => {
213
+ return await this.login(username, password);
214
+ },
215
+ signUp: async (username, password, confirm) => {
216
+ // For password-based signup, validate password confirmation
217
+ if (confirm && password !== confirm) {
218
+ throw new Error("Password and confirm password do not match");
219
+ }
220
+ return await this.signUp(username, password);
221
+ },
222
+ };
223
+ }
224
+ }
225
+ }