shogun-core 1.2.0 → 1.2.3
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 +6 -6
- package/dist/browser/shogun-core.js +1 -1
- package/dist/browser/shogun-core.light.js +1 -0
- package/dist/browser/shogun-core.vendors.light.js +1 -0
- package/dist/browser.js +11 -11
- package/dist/core.js +46 -45
- package/dist/gundb/gun.js +112 -92
- package/dist/plugins/index.js +4 -4
- package/dist/plugins/{bitcoin → nostr}/nostrConnectorPlugin.js +7 -8
- package/dist/plugins/{ethereum → web3}/web3ConnectorPlugin.js +7 -7
- package/dist/types/browser.d.ts +4 -4
- package/dist/types/core.d.ts +1 -2
- package/dist/types/gundb/gun.d.ts +4 -10
- package/dist/types/plugins/index.d.ts +6 -6
- package/dist/types/shogun.js +2 -2
- package/dist/types/types/shogun.d.ts +5 -23
- package/package.json +1 -1
- package/dist/gundb/models/auth/auth.js +0 -207
- package/dist/gundb/models/auth/state-machine.js +0 -216
- package/dist/gundb/models/streams.js +0 -116
- package/dist/types/gundb/models/auth/auth.d.ts +0 -121
- package/dist/types/gundb/models/auth/state-machine.d.ts +0 -70
- package/dist/types/gundb/models/streams.d.ts +0 -67
- /package/dist/plugins/{bitcoin → nostr}/index.js +0 -0
- /package/dist/plugins/{bitcoin → nostr}/nostrConnector.js +0 -0
- /package/dist/plugins/{bitcoin → nostr}/types.js +0 -0
- /package/dist/plugins/{ethereum → web3}/index.js +0 -0
- /package/dist/plugins/{ethereum → web3}/types.js +0 -0
- /package/dist/plugins/{ethereum → web3}/web3Connector.js +0 -0
- /package/dist/types/plugins/{bitcoin → nostr}/index.d.ts +0 -0
- /package/dist/types/plugins/{bitcoin → nostr}/nostrConnector.d.ts +0 -0
- /package/dist/types/plugins/{bitcoin → nostr}/nostrConnectorPlugin.d.ts +0 -0
- /package/dist/types/plugins/{bitcoin → nostr}/types.d.ts +0 -0
- /package/dist/types/plugins/{ethereum → web3}/index.d.ts +0 -0
- /package/dist/types/plugins/{ethereum → web3}/types.d.ts +0 -0
- /package/dist/types/plugins/{ethereum → web3}/web3Connector.d.ts +0 -0
- /package/dist/types/plugins/{ethereum → web3}/web3ConnectorPlugin.d.ts +0 -0
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GunDB class with enhanced features:
|
|
3
|
-
* - Dynamic auth token usage
|
|
4
|
-
* - Concurrency-safe authentication
|
|
5
3
|
* - Dynamic peer linking
|
|
6
4
|
* - Support for remove/unset operations
|
|
5
|
+
* - Direct authentication through Gun.user()
|
|
7
6
|
*/
|
|
8
7
|
import { IGunUserInstance, IGunInstance, IGunChain } from "gun";
|
|
9
8
|
import { GunRxJS } from "./rxjs-integration";
|
|
10
9
|
import * as GunErrors from "./errors";
|
|
11
10
|
import * as crypto from "./crypto";
|
|
12
11
|
import * as utils from "./utils";
|
|
13
|
-
import AuthManager from "./models/auth/auth";
|
|
14
12
|
declare class GunDB {
|
|
15
13
|
gun: IGunInstance<any>;
|
|
16
14
|
user: IGunUserInstance<any> | null;
|
|
17
15
|
crypto: typeof crypto;
|
|
18
16
|
utils: typeof utils;
|
|
19
|
-
auth: AuthManager;
|
|
20
17
|
node: IGunChain<any, IGunInstance<any>, IGunInstance<any>, string>;
|
|
21
18
|
private readonly onAuthCallbacks;
|
|
22
|
-
private _authenticating;
|
|
23
19
|
private _rxjs?;
|
|
24
20
|
constructor(gun: IGunInstance<any>, appScope?: string);
|
|
25
21
|
private subscribeToAuthEvents;
|
|
@@ -107,14 +103,14 @@ declare class GunDB {
|
|
|
107
103
|
*/
|
|
108
104
|
remove(path: string): Promise<any>;
|
|
109
105
|
/**
|
|
110
|
-
* Signs up a new user using
|
|
106
|
+
* Signs up a new user using direct Gun authentication
|
|
111
107
|
* @param username Username
|
|
112
108
|
* @param password Password
|
|
113
109
|
* @returns Promise resolving to signup result
|
|
114
110
|
*/
|
|
115
111
|
signUp(username: string, password: string): Promise<any>;
|
|
116
112
|
/**
|
|
117
|
-
* Logs in a user using
|
|
113
|
+
* Logs in a user using direct Gun authentication
|
|
118
114
|
* @param username Username
|
|
119
115
|
* @param password Password
|
|
120
116
|
* @param callback Optional callback for login result
|
|
@@ -122,10 +118,8 @@ declare class GunDB {
|
|
|
122
118
|
*/
|
|
123
119
|
login(username: string, password: string, callback?: (result: any) => void): Promise<any>;
|
|
124
120
|
private _savePair;
|
|
125
|
-
private isAuthenticating;
|
|
126
|
-
private _setAuthenticating;
|
|
127
121
|
/**
|
|
128
|
-
* Logs out the current user using
|
|
122
|
+
* Logs out the current user using direct Gun authentication
|
|
129
123
|
*/
|
|
130
124
|
logout(): void;
|
|
131
125
|
/**
|
|
@@ -3,9 +3,9 @@ export type { ShogunPlugin, PluginManager } from "../types/plugin";
|
|
|
3
3
|
export { Webauthn } from "./webauthn/webauthn";
|
|
4
4
|
export { WebauthnPlugin } from "./webauthn/webauthnPlugin";
|
|
5
5
|
export type { WebauthnPluginInterface } from "./webauthn/types";
|
|
6
|
-
export { Web3Connector } from "./
|
|
7
|
-
export { Web3ConnectorPlugin } from "./
|
|
8
|
-
export type { Web3ConectorPluginInterface } from "./
|
|
9
|
-
export { NostrConnector } from "./
|
|
10
|
-
export { NostrConnectorPlugin } from "./
|
|
11
|
-
export type { NostrConnectorPluginInterface, NostrConnectorCredentials, NostrConnectorKeyPair, NostrConnectorConfig, AlbyProvider, NostrProvider, } from "./
|
|
6
|
+
export { Web3Connector } from "./web3/web3Connector";
|
|
7
|
+
export { Web3ConnectorPlugin } from "./web3/web3ConnectorPlugin";
|
|
8
|
+
export type { Web3ConectorPluginInterface } from "./web3/types";
|
|
9
|
+
export { NostrConnector } from "./nostr/nostrConnector";
|
|
10
|
+
export { NostrConnectorPlugin } from "./nostr/nostrConnectorPlugin";
|
|
11
|
+
export type { NostrConnectorPluginInterface, NostrConnectorCredentials, NostrConnectorKeyPair, NostrConnectorConfig, AlbyProvider, NostrProvider, } from "./nostr/types";
|
package/dist/types/shogun.js
CHANGED
|
@@ -25,9 +25,9 @@ var CorePlugins;
|
|
|
25
25
|
/** WebAuthn plugin */
|
|
26
26
|
CorePlugins["WebAuthn"] = "webauthn";
|
|
27
27
|
/** Ethereum plugin */
|
|
28
|
-
CorePlugins["
|
|
28
|
+
CorePlugins["Web3"] = "web3";
|
|
29
29
|
/** Bitcoin wallet plugin */
|
|
30
|
-
CorePlugins["
|
|
30
|
+
CorePlugins["Nostr"] = "nostr";
|
|
31
31
|
})(CorePlugins || (exports.CorePlugins = CorePlugins = {}));
|
|
32
32
|
/**
|
|
33
33
|
* Authentication states for the state machine
|
|
@@ -27,11 +27,11 @@ export declare enum CorePlugins {
|
|
|
27
27
|
/** WebAuthn plugin */
|
|
28
28
|
WebAuthn = "webauthn",
|
|
29
29
|
/** Ethereum plugin */
|
|
30
|
-
|
|
30
|
+
Web3 = "web3",
|
|
31
31
|
/** Bitcoin wallet plugin */
|
|
32
|
-
|
|
32
|
+
Nostr = "nostr"
|
|
33
33
|
}
|
|
34
|
-
export type AuthMethod = "password" | "webauthn" | "
|
|
34
|
+
export type AuthMethod = "password" | "webauthn" | "web3" | "nostr";
|
|
35
35
|
export interface AuthResult {
|
|
36
36
|
success: boolean;
|
|
37
37
|
error?: string;
|
|
@@ -104,38 +104,20 @@ export interface ShogunSDKConfig {
|
|
|
104
104
|
gunInstance?: IGunInstance<any>;
|
|
105
105
|
scope?: string;
|
|
106
106
|
peers?: string[];
|
|
107
|
-
/** WebAuthn configuration */
|
|
108
107
|
webauthn?: WebauthnConfig;
|
|
109
|
-
|
|
110
|
-
ethereum?: {
|
|
111
|
-
/** Enable MetaMask */
|
|
108
|
+
web3?: {
|
|
112
109
|
enabled?: boolean;
|
|
113
110
|
};
|
|
114
|
-
|
|
115
|
-
bitcoin?: {
|
|
116
|
-
/** Enable Bitcoin wallet */
|
|
111
|
+
nostr?: {
|
|
117
112
|
enabled?: boolean;
|
|
118
|
-
/** Bitcoin network to use (default: mainnet) */
|
|
119
|
-
network?: "mainnet" | "testnet";
|
|
120
|
-
/** Use API for verification (default: false) */
|
|
121
|
-
useApi?: boolean;
|
|
122
|
-
/** API URL for verification */
|
|
123
|
-
apiUrl?: string;
|
|
124
113
|
};
|
|
125
|
-
/** Logging configuration */
|
|
126
114
|
logging?: LoggingConfig;
|
|
127
|
-
/** Timeout configuration in milliseconds */
|
|
128
115
|
timeouts?: {
|
|
129
|
-
/** Login timeout in milliseconds (default: 15000) */
|
|
130
116
|
login?: number;
|
|
131
|
-
/** Signup timeout in milliseconds (default: 20000) */
|
|
132
117
|
signup?: number;
|
|
133
|
-
/** General operation timeout in milliseconds (default: 30000) */
|
|
134
118
|
operation?: number;
|
|
135
119
|
};
|
|
136
|
-
/** Plugin configuration */
|
|
137
120
|
plugins?: {
|
|
138
|
-
/** List of plugins to automatically register on initialization */
|
|
139
121
|
autoRegister?: ShogunPlugin[];
|
|
140
122
|
};
|
|
141
123
|
}
|
package/package.json
CHANGED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const state_machine_1 = require("./state-machine");
|
|
4
|
-
// Simple helper function to replace app_scoped
|
|
5
|
-
function app_scoped(text, scope) {
|
|
6
|
-
return `${scope}_${text}`;
|
|
7
|
-
}
|
|
8
|
-
/** An auth manager that wraps gun.user logic. */
|
|
9
|
-
class AuthManager {
|
|
10
|
-
static INITIAL_STATE = state_machine_1.states.disconnected;
|
|
11
|
-
static state = (0, state_machine_1.use_machine)(state_machine_1.auth_state_machine, AuthManager.INITIAL_STATE);
|
|
12
|
-
static instance;
|
|
13
|
-
gundb;
|
|
14
|
-
app_scope = "shogun";
|
|
15
|
-
/** Returns the validated alias and password information. This will also be scoped using app_scope */
|
|
16
|
-
async validate(alias, password) {
|
|
17
|
-
if (password.length < 8)
|
|
18
|
-
throw new Error("Passwords in gun must be more than 8 characters long!");
|
|
19
|
-
if (alias.length < 1)
|
|
20
|
-
throw new Error("User name must be more than 0 characters long!");
|
|
21
|
-
const validated_alias = app_scoped(alias, this.app_scope);
|
|
22
|
-
const validated_password = app_scoped(password, this.app_scope);
|
|
23
|
-
return { alias: validated_alias, password: validated_password };
|
|
24
|
-
}
|
|
25
|
-
/** A new AuthManager. */
|
|
26
|
-
constructor(gundb, appScope = "shogun") {
|
|
27
|
-
if (AuthManager.instance) {
|
|
28
|
-
this.gundb = AuthManager.instance.gundb;
|
|
29
|
-
this.app_scope = AuthManager.instance.app_scope;
|
|
30
|
-
return AuthManager.instance;
|
|
31
|
-
}
|
|
32
|
-
this.gundb = gundb;
|
|
33
|
-
this.app_scope = appScope;
|
|
34
|
-
AuthManager.instance = this;
|
|
35
|
-
}
|
|
36
|
-
/** Gets the user chain, if authenticated. */
|
|
37
|
-
get chain() {
|
|
38
|
-
const pair = this.pair({ strict: true });
|
|
39
|
-
return this.gundb.gun.get(pair.pub);
|
|
40
|
-
}
|
|
41
|
-
pair(options = {}) {
|
|
42
|
-
const user = this.gundb.gun.user()._;
|
|
43
|
-
if ("sea" in user) {
|
|
44
|
-
return user.sea;
|
|
45
|
-
}
|
|
46
|
-
if (options.strict) {
|
|
47
|
-
throw new Error("Failed to get user pair! User is not authenticated");
|
|
48
|
-
}
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Generate a new gun user pair using alias and password.
|
|
53
|
-
*
|
|
54
|
-
* @param alias - The user alias.
|
|
55
|
-
* @param password - The user password.
|
|
56
|
-
* @returns A promise that resolves with gun ack or rejects with gun ack on errors.
|
|
57
|
-
*/
|
|
58
|
-
create = async ({ alias, password, }) => {
|
|
59
|
-
// Note: throws if state transitions is not possible.
|
|
60
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.create));
|
|
61
|
-
// attempt to create user.
|
|
62
|
-
try {
|
|
63
|
-
const res = await new Promise((resolve, reject) => {
|
|
64
|
-
this.gundb.gun.user().create(alias, password, (ack) => {
|
|
65
|
-
if ("err" in ack) {
|
|
66
|
-
reject(ack);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
resolve(ack);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
// creation success.
|
|
73
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
|
|
74
|
-
return res;
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
// creation failure.
|
|
78
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail, err));
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* Authenicate existing gun user using either a pair or a alias/password combination.
|
|
84
|
-
* @returns A promise that resolves with gun ack or rejects with gun ack on errors.
|
|
85
|
-
*/
|
|
86
|
-
auth = async (info) => {
|
|
87
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.authenticate));
|
|
88
|
-
// attempt to authenticate user.
|
|
89
|
-
try {
|
|
90
|
-
const res = await new Promise((resolve, reject) => {
|
|
91
|
-
if ("pub" in info) {
|
|
92
|
-
// Use auth with the pair directly to avoid type errors
|
|
93
|
-
// @ts-ignore - Ignoring type errors with GunDB's auth method
|
|
94
|
-
this.gundb.gun.user().auth(info, (ack) => {
|
|
95
|
-
if ("err" in ack) {
|
|
96
|
-
reject(new Error(ack.err));
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
else
|
|
100
|
-
resolve(ack);
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
// @ts-ignore - Ignoring type errors with GunDB's auth method
|
|
105
|
-
this.gundb.gun.user().auth(info.alias, info.password, (ack) => {
|
|
106
|
-
if ("err" in ack) {
|
|
107
|
-
reject(new Error(ack.err));
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
else
|
|
111
|
-
resolve(ack);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
// on auth success
|
|
116
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
|
|
117
|
-
return res;
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
// on auth error
|
|
121
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail));
|
|
122
|
-
throw err;
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
/**
|
|
126
|
-
* Un-authenticates the currently authenticated gun user.
|
|
127
|
-
*/
|
|
128
|
-
leave = async () => {
|
|
129
|
-
// check if state transition is possible.
|
|
130
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.disconnect));
|
|
131
|
-
// attempt log out.
|
|
132
|
-
try {
|
|
133
|
-
const res = await new Promise((resolve, reject) => {
|
|
134
|
-
this.gundb.gun.user().leave();
|
|
135
|
-
if (this.pair()?.pub) {
|
|
136
|
-
reject({ err: "User leave failed!" });
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
resolve({ success: true });
|
|
140
|
-
});
|
|
141
|
-
// on success.
|
|
142
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.success));
|
|
143
|
-
return res;
|
|
144
|
-
}
|
|
145
|
-
catch (err) {
|
|
146
|
-
// on fail.
|
|
147
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.fail));
|
|
148
|
-
throw err;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
* A simple default certificate that will allow everybody to write to the users graph, as long as the key or path contains their public key.
|
|
153
|
-
*/
|
|
154
|
-
certify() {
|
|
155
|
-
// Currently not implemented - needs to be added to the crypto module
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Start wallet initialization process
|
|
160
|
-
*/
|
|
161
|
-
startWalletInit() {
|
|
162
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_start));
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Mark wallet initialization as successful
|
|
166
|
-
*/
|
|
167
|
-
walletInitSuccess() {
|
|
168
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_success));
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Mark wallet initialization as failed
|
|
172
|
-
*/
|
|
173
|
-
walletInitFail(error) {
|
|
174
|
-
AuthManager.state.set(new state_machine_1.StateMachineEvent(state_machine_1.events.wallet_init_fail, error));
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Wait for authentication to complete
|
|
178
|
-
*/
|
|
179
|
-
async waitForAuthentication(timeoutMs = 10000) {
|
|
180
|
-
return AuthManager.state.waitForState(state_machine_1.states.authorized, timeoutMs);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Wait for wallet to be ready
|
|
184
|
-
*/
|
|
185
|
-
async waitForWalletReady(timeoutMs = 15000) {
|
|
186
|
-
return AuthManager.state.waitForState(state_machine_1.states.wallet_ready, timeoutMs);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Check if user is authenticated
|
|
190
|
-
*/
|
|
191
|
-
isAuthenticated() {
|
|
192
|
-
return AuthManager.state.isAuthenticated();
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Check if wallet is ready
|
|
196
|
-
*/
|
|
197
|
-
isWalletReady() {
|
|
198
|
-
return AuthManager.state.isWalletReady();
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Get current authentication state
|
|
202
|
-
*/
|
|
203
|
-
getCurrentState() {
|
|
204
|
-
return AuthManager.state.getCurrentState();
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
exports.default = AuthManager;
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.events = exports.states = exports.StateMachineEvent = void 0;
|
|
4
|
-
exports.use_machine = use_machine;
|
|
5
|
-
exports.auth_state_machine = auth_state_machine;
|
|
6
|
-
/** A state machine event with optional data */
|
|
7
|
-
class StateMachineEvent {
|
|
8
|
-
type;
|
|
9
|
-
data;
|
|
10
|
-
constructor(type, data = {}) {
|
|
11
|
-
this.type = type;
|
|
12
|
-
this.data = data;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
exports.StateMachineEvent = StateMachineEvent;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param machine - A machine function that defines state transitions.
|
|
19
|
-
* @param initial - The initial state of the machine.
|
|
20
|
-
*/
|
|
21
|
-
function use_machine(machine, initial) {
|
|
22
|
-
let state = initial;
|
|
23
|
-
let subs = new Map();
|
|
24
|
-
let stateWaiters = new Map();
|
|
25
|
-
function subscribe(cb) {
|
|
26
|
-
const id = crypto.randomUUID();
|
|
27
|
-
subs.set(id, cb);
|
|
28
|
-
cb(state);
|
|
29
|
-
return () => {
|
|
30
|
-
subs.delete(id);
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function set(event) {
|
|
34
|
-
const previousState = state;
|
|
35
|
-
state = machine(state, event);
|
|
36
|
-
// Notify subscribers
|
|
37
|
-
for (const sub of subs.values()) {
|
|
38
|
-
sub(state);
|
|
39
|
-
}
|
|
40
|
-
// Notify state waiters
|
|
41
|
-
const waiters = stateWaiters.get(state);
|
|
42
|
-
if (waiters) {
|
|
43
|
-
waiters.forEach((resolve) => resolve(true));
|
|
44
|
-
stateWaiters.delete(state);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function getCurrentState() {
|
|
48
|
-
return state;
|
|
49
|
-
}
|
|
50
|
-
function waitForState(targetState, timeoutMs = 10000) {
|
|
51
|
-
return new Promise((resolve) => {
|
|
52
|
-
// If already in target state, resolve immediately
|
|
53
|
-
if (state === targetState) {
|
|
54
|
-
resolve(true);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
// Add to waiters
|
|
58
|
-
if (!stateWaiters.has(targetState)) {
|
|
59
|
-
stateWaiters.set(targetState, []);
|
|
60
|
-
}
|
|
61
|
-
stateWaiters.get(targetState).push(resolve);
|
|
62
|
-
// Set timeout
|
|
63
|
-
setTimeout(() => {
|
|
64
|
-
const waiters = stateWaiters.get(targetState);
|
|
65
|
-
if (waiters) {
|
|
66
|
-
const index = waiters.indexOf(resolve);
|
|
67
|
-
if (index > -1) {
|
|
68
|
-
waiters.splice(index, 1);
|
|
69
|
-
if (waiters.length === 0) {
|
|
70
|
-
stateWaiters.delete(targetState);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
resolve(false);
|
|
75
|
-
}, timeoutMs);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
function isAuthenticated() {
|
|
79
|
-
return (state === exports.states.authorized ||
|
|
80
|
-
state === exports.states.wallet_initializing ||
|
|
81
|
-
state === exports.states.wallet_ready);
|
|
82
|
-
}
|
|
83
|
-
function isWalletReady() {
|
|
84
|
-
return state === exports.states.wallet_ready;
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
/**
|
|
88
|
-
* Subscribe to state updates.
|
|
89
|
-
* @returns an unsubscriber */
|
|
90
|
-
subscribe,
|
|
91
|
-
/** attempt to update the state machine */
|
|
92
|
-
set,
|
|
93
|
-
/** Get the current state */
|
|
94
|
-
getCurrentState,
|
|
95
|
-
/** Wait for a specific state */
|
|
96
|
-
waitForState,
|
|
97
|
-
/** Check if user is authenticated */
|
|
98
|
-
isAuthenticated,
|
|
99
|
-
/** Check if wallet is ready */
|
|
100
|
-
isWalletReady,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/** Possible states that the auth-manager can be in. */
|
|
104
|
-
exports.states = {
|
|
105
|
-
/** The user is in an un-busy and unauthorized state.*/
|
|
106
|
-
disconnected: "disconnected",
|
|
107
|
-
/** A user is currently being created. */
|
|
108
|
-
creating: "creating",
|
|
109
|
-
/** A user is currently being authorized. */
|
|
110
|
-
pending: "pending",
|
|
111
|
-
/** The user is in an un-busy and authorized state. */
|
|
112
|
-
authorized: "authorized",
|
|
113
|
-
/** The user is currently logging out. */
|
|
114
|
-
leaving: "leaving",
|
|
115
|
-
/** Wallet initialization is in progress. */
|
|
116
|
-
wallet_initializing: "wallet_initializing",
|
|
117
|
-
/** Wallet is ready and available. */
|
|
118
|
-
wallet_ready: "wallet_ready",
|
|
119
|
-
};
|
|
120
|
-
/** Possible events that the auth-manager can take. */
|
|
121
|
-
exports.events = {
|
|
122
|
-
create: "create",
|
|
123
|
-
authenticate: "authenticate",
|
|
124
|
-
disconnect: "disconnect",
|
|
125
|
-
fail: "fail",
|
|
126
|
-
success: "success",
|
|
127
|
-
wallet_init_start: "wallet_init_start",
|
|
128
|
-
wallet_init_success: "wallet_init_success",
|
|
129
|
-
wallet_init_fail: "wallet_init_fail",
|
|
130
|
-
};
|
|
131
|
-
class StateTransitionError extends Error {
|
|
132
|
-
state;
|
|
133
|
-
event;
|
|
134
|
-
constructor(message, state, event) {
|
|
135
|
-
super(message);
|
|
136
|
-
this.state = state;
|
|
137
|
-
this.event = event;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Defines possible transitions from the states in the auth manager.
|
|
142
|
-
*
|
|
143
|
-
* @param state - The current state.
|
|
144
|
-
* @param event The event that has happend.
|
|
145
|
-
* @returns The new state.
|
|
146
|
-
*/
|
|
147
|
-
function auth_state_machine(state, event) {
|
|
148
|
-
const transition_error = new StateTransitionError("Not a valid state transition", state, event.type);
|
|
149
|
-
switch (state) {
|
|
150
|
-
// User is disconnected and unbusy
|
|
151
|
-
case exports.states.disconnected:
|
|
152
|
-
if (event.type === exports.events.create) {
|
|
153
|
-
return exports.states.creating;
|
|
154
|
-
}
|
|
155
|
-
if (event.type === exports.events.authenticate) {
|
|
156
|
-
return exports.states.pending;
|
|
157
|
-
}
|
|
158
|
-
throw transition_error;
|
|
159
|
-
// User is creating and busy
|
|
160
|
-
case exports.states.creating:
|
|
161
|
-
if (event.type === exports.events.fail) {
|
|
162
|
-
return exports.states.disconnected;
|
|
163
|
-
}
|
|
164
|
-
if (event.type === exports.events.success) {
|
|
165
|
-
return exports.states.disconnected;
|
|
166
|
-
}
|
|
167
|
-
throw transition_error;
|
|
168
|
-
// User is logging in and busy
|
|
169
|
-
case exports.states.pending:
|
|
170
|
-
if (event.type === exports.events.fail) {
|
|
171
|
-
return exports.states.disconnected;
|
|
172
|
-
}
|
|
173
|
-
if (event.type === exports.events.success) {
|
|
174
|
-
return exports.states.authorized;
|
|
175
|
-
}
|
|
176
|
-
throw transition_error;
|
|
177
|
-
// User is authorized and unbusy
|
|
178
|
-
case exports.states.authorized:
|
|
179
|
-
if (event.type === exports.events.disconnect) {
|
|
180
|
-
return exports.states.leaving;
|
|
181
|
-
}
|
|
182
|
-
if (event.type === exports.events.wallet_init_start) {
|
|
183
|
-
return exports.states.wallet_initializing;
|
|
184
|
-
}
|
|
185
|
-
throw transition_error;
|
|
186
|
-
// User is leaving and busy
|
|
187
|
-
case exports.states.leaving:
|
|
188
|
-
if (event.type === exports.events.fail) {
|
|
189
|
-
return exports.states.authorized;
|
|
190
|
-
}
|
|
191
|
-
if (event.type === exports.events.success) {
|
|
192
|
-
return exports.states.disconnected;
|
|
193
|
-
}
|
|
194
|
-
throw transition_error;
|
|
195
|
-
// Wallet is being initialized
|
|
196
|
-
case exports.states.wallet_initializing:
|
|
197
|
-
if (event.type === exports.events.wallet_init_success) {
|
|
198
|
-
return exports.states.wallet_ready;
|
|
199
|
-
}
|
|
200
|
-
if (event.type === exports.events.wallet_init_fail) {
|
|
201
|
-
return exports.states.authorized;
|
|
202
|
-
}
|
|
203
|
-
if (event.type === exports.events.disconnect) {
|
|
204
|
-
return exports.states.leaving;
|
|
205
|
-
}
|
|
206
|
-
throw transition_error;
|
|
207
|
-
// Wallet is ready
|
|
208
|
-
case exports.states.wallet_ready:
|
|
209
|
-
if (event.type === exports.events.disconnect) {
|
|
210
|
-
return exports.states.leaving;
|
|
211
|
-
}
|
|
212
|
-
throw transition_error;
|
|
213
|
-
default:
|
|
214
|
-
throw transition_error;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.on_stream = on_stream;
|
|
4
|
-
exports.to_unique = to_unique;
|
|
5
|
-
exports.to_node = to_node;
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* Only Firefox implements async iterable on ReadableStream. This will add polyfill.
|
|
9
|
-
*
|
|
10
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream#browser_compatibility
|
|
11
|
-
*/
|
|
12
|
-
(function enable_async_iterator_polyfill() {
|
|
13
|
-
ReadableStream.prototype[Symbol.asyncIterator] = async function* () {
|
|
14
|
-
const reader = this.getReader();
|
|
15
|
-
try {
|
|
16
|
-
while (true) {
|
|
17
|
-
const { done, value } = await reader.read();
|
|
18
|
-
if (done)
|
|
19
|
-
return;
|
|
20
|
-
yield value;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
finally {
|
|
24
|
-
reader.releaseLock();
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
})();
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
* Wraps .on call in a stream. Cancelling the stream will unsubscribe from updates from gun.
|
|
31
|
-
*
|
|
32
|
-
* **Usage:**
|
|
33
|
-
* ```
|
|
34
|
-
* const stream = on_stream(node)
|
|
35
|
-
* for await (const chunk of stream) {
|
|
36
|
-
* // Do something with each 'chunk'
|
|
37
|
-
* }
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
function on_stream(chain) {
|
|
41
|
-
let ev;
|
|
42
|
-
const stream = new ReadableStream({
|
|
43
|
-
start(controller) {
|
|
44
|
-
console.log("stream started");
|
|
45
|
-
chain.on(function (value, key, _, event) {
|
|
46
|
-
ev = event;
|
|
47
|
-
console.log(`from stream, ${key}`);
|
|
48
|
-
controller.enqueue({ value, key, chain: this });
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
cancel() {
|
|
52
|
-
console.log("stream cancelled");
|
|
53
|
-
if (!ev) {
|
|
54
|
-
// TODO log
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
ev.off();
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
return stream;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
*
|
|
64
|
-
* Takes an incoming stream, but only issues updates if the data changes from valid data to null data.
|
|
65
|
-
* You can use this to keep a list in sync with the gun state. If data is tombstoned, it can be removed from the list.
|
|
66
|
-
*
|
|
67
|
-
* **Example:**
|
|
68
|
-
* ```
|
|
69
|
-
* const map = new Map();
|
|
70
|
-
* const items = [];
|
|
71
|
-
* const stream = on_stream(node).pipeThrough(unique_transformer());
|
|
72
|
-
* for await (const chunk of stream) {
|
|
73
|
-
* chunk.value === null ? map.delete(chunk.key) : map.set(chunk.key, chunk.chain);
|
|
74
|
-
items.splice(0, items.length, ...map.values());
|
|
75
|
-
* }
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
function to_unique() {
|
|
79
|
-
const map = new Map();
|
|
80
|
-
const transformer = new TransformStream({
|
|
81
|
-
transform(chuck, controller) {
|
|
82
|
-
if (!map.has(chuck.key)) {
|
|
83
|
-
pass(controller, chuck);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const old_value = map.get(chuck.key);
|
|
87
|
-
if (chuck.value === null && old_value !== null) {
|
|
88
|
-
pass(controller, chuck);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (chuck.value !== null && old_value === null) {
|
|
92
|
-
pass(controller, chuck);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
function pass(controller, chuck) {
|
|
96
|
-
map.set(chuck.key, chuck.chain);
|
|
97
|
-
controller.enqueue(chuck);
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
return transformer;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Transoforms a stream of gun chains into a stream of gun nodes.
|
|
105
|
-
*/
|
|
106
|
-
function to_node(target) {
|
|
107
|
-
const transformer = new TransformStream({
|
|
108
|
-
transform(chunk, controller) {
|
|
109
|
-
const new_chunk = chunk.chain
|
|
110
|
-
? { value: chunk.value, key: chunk.key, node: new target(chunk.chain) }
|
|
111
|
-
: { value: chunk.value, key: chunk.key, node: chunk.chain };
|
|
112
|
-
controller.enqueue(new_chunk);
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
return transformer;
|
|
116
|
-
}
|